Compare commits
14 Commits
v3.0-alpha
...
v3.1
Author | SHA1 | Date | |
---|---|---|---|
0be036fcea | |||
e153e51abd | |||
d292ce389a | |||
807e006245 | |||
8d7a982e50 | |||
ddf6b7befe | |||
a300ddbb49 | |||
c9e51c9b6a | |||
b58f837a94 | |||
5fe865c621 | |||
9b9fc9cde8 | |||
ef459a210d | |||
7680d11c0e | |||
e7376a3e9c |
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.)
|
||||
|
20
README.md
@ -15,7 +15,7 @@ This plugin contain various aspect of Ballance mapping. However, if some feature
|
||||
|
||||
Used BM file spec can be found in [there](https://github.com/yyc12345/gist/blob/master/BMFileSpec/BMSpec_ZH.md) (Chinese only).
|
||||
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)
|
||||
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**.
|
||||
|
||||
@ -110,25 +110,21 @@ In default, user created material will not enable Virtools Material feature. You
|
||||
|
||||
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.
|
||||
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
|
||||
|
||||
|
19
README_ZH.md
@ -110,6 +110,7 @@ Ballance 3D是一套简单的用于制图3D相关的轻型工具集合,可以
|
||||
|
||||
在启用Virtools Material后,可以在`Basic Parameters`和`Advanced Parameters`中设置材质属性,就像在Virtools中操作一般。
|
||||
`Basic Parameters`是基础材质属性。`Advanced Parameters`则是与透明相关的材质属性,主要用于半透明柱子底部等。
|
||||
另外,`Basic Parameters`部分提供了预设功能,允许用户使用一些预设的材质设置,这些设置只影响4种基本颜色,方便使用。
|
||||
|
||||
`Operation`中的`Apply Virtools Material`将把Virtools Material应用到Blender材质上。
|
||||
而`Parse from Blender Principled BSDF`将尝试将一个原理化BSDF转换为Virtools材质数据。
|
||||
@ -117,21 +118,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):
|
||||
|
@ -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
|
||||
|
@ -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,6 +18,7 @@ class BALLANCE_OT_super_align(bpy.types.Operator):
|
||||
('POINT', "Center (axis)", ""),
|
||||
('MAX', "Max", "")
|
||||
),
|
||||
default='POINT',
|
||||
)
|
||||
|
||||
target_references: bpy.props.EnumProperty(
|
||||
@ -27,6 +28,7 @@ class BALLANCE_OT_super_align(bpy.types.Operator):
|
||||
('POINT', "Center (axis)", ""),
|
||||
('MAX', "Max", "")
|
||||
),
|
||||
default='POINT',
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -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,12 +1,26 @@
|
||||
import bpy,mathutils
|
||||
import bmesh
|
||||
import math
|
||||
from . import UTILS_functions
|
||||
|
||||
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'}
|
||||
|
||||
normal_scale_correction = 5.0
|
||||
sink_scale_correction = 5.0 * (math.sqrt(2.5 ** 2 + 0.7 ** 2) / 2.5)
|
||||
|
||||
scale_correction: bpy.props.EnumProperty(
|
||||
name="Scale Correction",
|
||||
description="Choose your UV scale.",
|
||||
items=(
|
||||
("NORMAL", "Normal Floor", "Normal floor scale, 5.0"),
|
||||
("SINK", "Sink Floor", "Sink floor scale, around 5.19")
|
||||
),
|
||||
default='NORMAL',
|
||||
)
|
||||
|
||||
reference_edge : bpy.props.IntProperty(
|
||||
name="Reference edge",
|
||||
@ -20,7 +34,7 @@ class BALLANCE_OT_flatten_uv(bpy.types.Operator):
|
||||
@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 +42,26 @@ 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 get_scale_correction(self):
|
||||
if self.scale_correction == 'NORMAL':
|
||||
return BALLANCE_OT_flatten_uv.normal_scale_correction
|
||||
elif self.scale_correction == 'SINK':
|
||||
return BALLANCE_OT_flatten_uv.sink_scale_correction
|
||||
else:
|
||||
raise Exception("Unknow scale correction.")
|
||||
|
||||
def execute(self, context):
|
||||
no_processed_count = _real_flatten_uv(bpy.context.active_object.data, self.reference_edge)
|
||||
no_processed_count = _real_flatten_uv(bpy.context.active_object.data, self.reference_edge, self.get_scale_correction())
|
||||
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.prop(self, "scale_correction")
|
||||
layout.prop(self, "reference_edge")
|
||||
|
||||
def _real_flatten_uv(mesh, reference_edge):
|
||||
def _real_flatten_uv(mesh, reference_edge, scale_correction):
|
||||
no_processed_count = 0
|
||||
|
||||
if mesh.uv_layers.active is None:
|
||||
@ -58,13 +74,26 @@ def _real_flatten_uv(mesh, reference_edge):
|
||||
if not face.select:
|
||||
continue
|
||||
|
||||
# check whether ref edge is legal
|
||||
allPoint = len(face.loops)
|
||||
|
||||
if allPoint <= reference_edge:
|
||||
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 exceptio
|
||||
# just a weird uv. user will notice this problem.
|
||||
|
||||
# get point
|
||||
p1Relative = reference_edge
|
||||
p2Relative = reference_edge + 1
|
||||
p3Relative = reference_edge + 2
|
||||
@ -77,13 +106,19 @@ def _real_flatten_uv(mesh, reference_edge):
|
||||
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):
|
||||
new_z_axis = face.normal.normalized()
|
||||
|
||||
# get x axis
|
||||
new_x_axis = new_y_axis.cross(new_z_axis)
|
||||
new_x_axis.normalize()
|
||||
|
||||
@ -93,14 +128,14 @@ 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
|
||||
for loop_index in range(allPoint):
|
||||
@ -108,9 +143,11 @@ def _real_flatten_uv(mesh, reference_edge):
|
||||
vec = pp-p1
|
||||
new_vec = transition_matrix @ vec
|
||||
|
||||
# y axis always use 5.0 to scale
|
||||
# however, x need use custom scale correction.
|
||||
face.loops[loop_index][uv_lay].uv = (
|
||||
(new_vec.x if new_vec.x >=0 else -new_vec.x) / 5,
|
||||
(new_vec.y) / 5
|
||||
(new_vec.x if new_vec.x >=0 else -new_vec.x) / scale_correction,
|
||||
(new_vec.y) / 5.0
|
||||
)
|
||||
|
||||
# Show the updates in the viewport
|
||||
|
@ -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'}
|
||||
@ -175,7 +175,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
|
||||
|
||||
# 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()
|
||||
|
||||
_set_data(obj, info, dest_std)
|
||||
|
||||
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,43 +1,124 @@
|
||||
import bpy, mathutils
|
||||
from . import UTILS_constants, UTILS_functions
|
||||
from . import UTILS_constants, UTILS_functions, UTILS_icons_manager
|
||||
|
||||
# ================================================= actual add
|
||||
# =============== Common Class ================
|
||||
class common_add_component_props(bpy.types.Operator):
|
||||
attentionElements = ("PC_TwoFlames", "PR_Resetpoint")
|
||||
uniqueElements = ("PS_FourFlames", "PE_Balloon")
|
||||
|
||||
class BALLANCE_OT_add_components(bpy.types.Operator):
|
||||
"""Add sector related elements"""
|
||||
elements_sector: bpy.props.IntProperty(
|
||||
name="Sector",
|
||||
description="Define which sector the object will be grouped in",
|
||||
min=1, max=8,
|
||||
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_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)),
|
||||
)
|
||||
|
||||
attentionElements = ["PC_TwoFlames", "PR_Resetpoint"]
|
||||
uniqueElements = ["PS_FourFlames", "PE_Balloon"]
|
||||
|
||||
elements_sector: bpy.props.IntProperty(
|
||||
name="Sector",
|
||||
description="Define which sector the object will be grouped in",
|
||||
min=1,
|
||||
max=8,
|
||||
default=1,
|
||||
#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)
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
wm = context.window_manager
|
||||
return wm.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
# attension notice
|
||||
if self.elements_type in self.attentionElements:
|
||||
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")
|
||||
self.parent_draw(layout, self.elements_type)
|
||||
|
||||
@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)
|
||||
|
||||
@ -50,7 +131,104 @@ class BALLANCE_OT_add_components(bpy.types.Operator):
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.prop(self, "elements_type")
|
||||
if self.elements_type not in self.uniqueElements:
|
||||
layout.prop(self, "elements_sector")
|
||||
if self.elements_type in self.attentionElements:
|
||||
layout.label(text="Please note that sector is suffix.")
|
||||
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
|
||||
|
@ -10,55 +10,41 @@ class BALLANCE_OT_add_rails(bpy.types.Operator):
|
||||
rail_type: bpy.props.EnumProperty(
|
||||
name="Type",
|
||||
description="Rail type",
|
||||
items=(('MONO', "Monorail", ""),
|
||||
items=(
|
||||
('MONO', "Monorail", ""),
|
||||
('DOUBLE', "Rail", ""),
|
||||
),
|
||||
default='DOUBLE',
|
||||
)
|
||||
|
||||
rail_radius: bpy.props.FloatProperty(
|
||||
name="Rail radius",
|
||||
name="Rail Radius",
|
||||
description="Define rail section radius",
|
||||
default=0.375,
|
||||
)
|
||||
|
||||
rail_span: bpy.props.FloatProperty(
|
||||
name="Rail span",
|
||||
description="Define rail span",
|
||||
name="Rail Span",
|
||||
description="The length between 2 single rails.",
|
||||
default=3.75,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
# create one first
|
||||
bpy.ops.mesh.primitive_circle_add(vertices=8,
|
||||
radius=self.rail_radius,
|
||||
fill_type='NOTHING',
|
||||
calc_uvs=False,
|
||||
enter_editmode=False,
|
||||
align='WORLD',
|
||||
location=(0.0, 0.0, 0.0))
|
||||
|
||||
firstObj = bpy.context.selected_objects[0]
|
||||
firstObj = _create_ballance_circle(self.rail_radius, (0.0, 0.0, 0.0))
|
||||
|
||||
# for double rail
|
||||
if self.rail_type == 'DOUBLE':
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
bpy.ops.mesh.primitive_circle_add(vertices=8,
|
||||
radius=self.rail_radius,
|
||||
fill_type='NOTHING',
|
||||
calc_uvs=False,
|
||||
enter_editmode=False,
|
||||
align='WORLD',
|
||||
location=(self.rail_span, 0.0, 0.0))
|
||||
secondObj = bpy.context.selected_objects[0]
|
||||
|
||||
# create another one
|
||||
secondObj = _create_ballance_circle(self.rail_radius, (self.rail_span, 0.0, 0.0))
|
||||
# merge
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
bpy.context.view_layer.objects.active = firstObj
|
||||
firstObj.select_set(True)
|
||||
secondObj.select_set(True)
|
||||
bpy.ops.object.join()
|
||||
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)
|
||||
|
||||
@ -75,3 +61,80 @@ class BALLANCE_OT_add_rails(bpy.types.Operator):
|
||||
if self.rail_type == 'DOUBLE':
|
||||
layout.prop(self, "rail_span")
|
||||
|
||||
class BALLANCE_OT_add_tunnels(bpy.types.Operator):
|
||||
"""Add rail"""
|
||||
bl_idname = "ballance.add_tunnels"
|
||||
bl_label = "Add tunnel section"
|
||||
bl_options = {'UNDO'}
|
||||
|
||||
use_outside: bpy.props.BoolProperty(
|
||||
name="Double Sides",
|
||||
description="Create tunnel section with double sides, not a single face.",
|
||||
default=True,
|
||||
)
|
||||
|
||||
inside_radius: bpy.props.FloatProperty(
|
||||
name="Inside Radius",
|
||||
description="Tunnel inside radius",
|
||||
default=2.5,
|
||||
)
|
||||
|
||||
outside_radius: bpy.props.FloatProperty(
|
||||
name="Outside Radius",
|
||||
description="Tunnel outside radius",
|
||||
default=2.6,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
# create one first
|
||||
firstObj = _create_ballance_circle(self.inside_radius, (0.0, 0.0, 0.0))
|
||||
|
||||
# for double rail
|
||||
if self.use_outside:
|
||||
# create another one
|
||||
secondObj = _create_ballance_circle(self.outside_radius, (0.0, 0.0, 0.0))
|
||||
# merge
|
||||
firstObj = _merge_two_circle(firstObj, secondObj)
|
||||
|
||||
# rename
|
||||
firstObj.name = "A_Rail_Tunnel_"
|
||||
# apply 3d cursor
|
||||
UTILS_functions.move_to_cursor(firstObj)
|
||||
|
||||
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, "use_outside")
|
||||
layout.prop(self, "inside_radius")
|
||||
if self.use_outside:
|
||||
layout.prop(self, "outside_radius")
|
||||
|
||||
def _create_ballance_circle(radius, loc):
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
bpy.ops.mesh.primitive_circle_add(
|
||||
vertices=8,
|
||||
radius=radius,
|
||||
fill_type='NOTHING',
|
||||
calc_uvs=False,
|
||||
enter_editmode=False,
|
||||
align='WORLD',
|
||||
location=loc
|
||||
)
|
||||
|
||||
created_obj = bpy.context.selected_objects[0]
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
return created_obj
|
||||
|
||||
def _merge_two_circle(obj1, obj2):
|
||||
bpy.ops.object.select_all(action='DESELECT')
|
||||
bpy.context.view_layer.objects.active = obj1
|
||||
obj1.select_set(True)
|
||||
obj2.select_set(True)
|
||||
bpy.ops.object.join()
|
||||
|
||||
return obj1
|
||||
|
@ -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):
|
||||
if self.selection_type == 'SET':
|
||||
# iterate object
|
||||
for obj in bpy.context.scene.objects:
|
||||
# ignore hidden objects
|
||||
if (not self.ignore_hide) and obj.hide_get() == True:
|
||||
continue
|
||||
# check group and decide whether select this obj
|
||||
obj.select_set(UTILS_virtools_prop.check_virtools_group_data(obj, self.get_group_name_string()))
|
||||
|
||||
# check group
|
||||
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()):
|
||||
# select object
|
||||
obj.select_set(True)
|
||||
else:
|
||||
# if not in merge mode, deselect them
|
||||
if not self.merge_selection:
|
||||
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)
|
||||
|
||||
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,9 +169,10 @@ 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",
|
||||
@ -186,6 +187,7 @@ floor_materialStatistic = [
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Floor Top",
|
||||
"member": [
|
||||
"FloorTopBorder",
|
||||
"FloorTopBorderless",
|
||||
@ -202,6 +204,7 @@ floor_materialStatistic = [
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Transform Paper",
|
||||
"member": [
|
||||
"BallPaper"
|
||||
],
|
||||
@ -214,6 +217,7 @@ floor_materialStatistic = [
|
||||
}
|
||||
},
|
||||
{
|
||||
"human-readable": "Transform Stone & Wood",
|
||||
"member": [
|
||||
"BallStone",
|
||||
"BallWood"
|
||||
@ -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',
|
||||
@ -127,9 +140,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 = []
|
||||
faceList = []
|
||||
@ -204,6 +214,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",
|
||||
ambient: bpy.props.FloatVectorProperty(
|
||||
name="Ambient",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.0])
|
||||
default=[76 / 255, 76 / 255, 76 / 255]
|
||||
)
|
||||
|
||||
diffuse: bpy.props.FloatVectorProperty(name="Diffuse",
|
||||
diffuse: bpy.props.FloatVectorProperty(
|
||||
name="Diffuse",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.0])
|
||||
default=[178 / 255, 178 / 255, 178 / 255]
|
||||
)
|
||||
|
||||
specular: bpy.props.FloatVectorProperty(name="Specular",
|
||||
specular: bpy.props.FloatVectorProperty(
|
||||
name="Specular",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.0])
|
||||
default=[127 / 255, 127 / 255, 127 / 255]
|
||||
)
|
||||
|
||||
emissive: bpy.props.FloatVectorProperty(name="Emissive",
|
||||
emissive: bpy.props.FloatVectorProperty(
|
||||
name="Emissive",
|
||||
subtype='COLOR',
|
||||
min=0.0,
|
||||
max=1.0,
|
||||
default=[0.0,0.0,0.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(
|
||||
@ -98,7 +111,7 @@ class common_group_name_props(bpy.types.Operator):
|
||||
if (self.group_name_source == 'CUSTOM'):
|
||||
parent_layout.prop(self, 'custom_group_name')
|
||||
else:
|
||||
parent_layout.prop(self, 'group_name')
|
||||
parent_layout.prop(self, 'group_name') # do not translate group name. it's weird
|
||||
|
||||
def get_group_name_string(self):
|
||||
return str(self.custom_group_name if self.group_name_source == 'CUSTOM' else self.group_name)
|
||||
|
@ -2,7 +2,7 @@ bl_info={
|
||||
"name":"Ballance Blender Plugin",
|
||||
"description":"Ballance mapping tools for Blender",
|
||||
"author":"yyc12345",
|
||||
"version":(3,0),
|
||||
"version":(3,1),
|
||||
"blender":(3,3,0),
|
||||
"category":"Object",
|
||||
"support":"TESTING",
|
||||
@ -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,9 +106,50 @@ 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"""
|
||||
bl_idname = "BALLANCE_MT_AddRailMenu"
|
||||
bl_label = "Rails"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
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
|
||||
@ -125,9 +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,
|
||||
@ -137,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,
|
||||
@ -162,11 +210,12 @@ def menu_func_ballance_add(self, context):
|
||||
layout = self.layout
|
||||
layout.separator()
|
||||
layout.label(text="Ballance")
|
||||
layout.operator_menu_enum(
|
||||
OBJS_add_components.BALLANCE_OT_add_components.bl_idname,
|
||||
"elements_type", icon='MESH_ICOSPHERE', text="Elements")
|
||||
layout.operator(OBJS_add_rails.BALLANCE_OT_add_rails.bl_idname, icon='MESH_CIRCLE', text="Rail section")
|
||||
layout.menu(BALLANCE_MT_AddFloorMenu.bl_idname, icon='MESH_CUBE')
|
||||
layout.menu(BALLANCE_MT_AddRailMenu.bl_idname, icon='MESH_CIRCLE')
|
||||
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()
|
||||
@ -180,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()
|
||||
@ -195,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)
|
||||
@ -241,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 |