fix issues
- apply transform when creating BME struct's vertices and faces. - add 3ds max align operator. support Apply button in a nasty way.
This commit is contained in:
parent
50b7eb0bce
commit
9315ff723d
@ -47,7 +47,7 @@ class BBP_OT_add_bme_struct(bpy.types.Operator):
|
|||||||
# In this internal cache list updator, check "outdated" flag first, if cache is outdated, update and reset flag.
|
# In this internal cache list updator, check "outdated" flag first, if cache is outdated, update and reset flag.
|
||||||
# Otherwise do nothing.
|
# Otherwise do nothing.
|
||||||
#
|
#
|
||||||
# Reference: https://docs.blender.org/api/current/bpy.props.html#update-example
|
# Reference: https://docs.blender.org/api/current/bpy.props.html#update-example
|
||||||
|
|
||||||
## Compromise used "outdated" flag.
|
## Compromise used "outdated" flag.
|
||||||
outdated_flag: bpy.props.BoolProperty(
|
outdated_flag: bpy.props.BoolProperty(
|
||||||
|
255
bbp_ng/OP_OBJECT_legacy_align.py
Normal file
255
bbp_ng/OP_OBJECT_legacy_align.py
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
import bpy, mathutils
|
||||||
|
import enum, typing
|
||||||
|
from . import UTIL_functions
|
||||||
|
|
||||||
|
#region Align Mode
|
||||||
|
|
||||||
|
class AlignMode(enum.IntEnum):
|
||||||
|
Min = enum.auto()
|
||||||
|
BBoxCenter = enum.auto()
|
||||||
|
AxisCenter = enum.auto()
|
||||||
|
Max = enum.auto()
|
||||||
|
_g_AlignModeDesc: dict[AlignMode, tuple[str, str]] = {
|
||||||
|
AlignMode.Min: ("Min", "The min value in specified axis."),
|
||||||
|
AlignMode.BBoxCenter: ("Center (Bounding Box)", "The bounding box center in specified axis."),
|
||||||
|
AlignMode.AxisCenter: ("Center (Axis)", "The object's source point in specified axis."),
|
||||||
|
AlignMode.Max: ("Max", "The max value in specified axis."),
|
||||||
|
}
|
||||||
|
_g_EnumHelper_AlignMode: UTIL_functions.EnumPropHelper = UTIL_functions.EnumPropHelper(
|
||||||
|
AlignMode,
|
||||||
|
lambda x: str(x.value),
|
||||||
|
lambda x: AlignMode(int(x)),
|
||||||
|
lambda x: _g_AlignModeDesc[x][0],
|
||||||
|
lambda x: _g_AlignModeDesc[x][1],
|
||||||
|
lambda _: ''
|
||||||
|
)
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Align Cache Implement
|
||||||
|
|
||||||
|
## As we known, 3ds Max's align window have a Apply button which can apply current align to scene,
|
||||||
|
# and user call set next align settings after clicking Apply. It will not affect previous set align settings.
|
||||||
|
# But Blender have no vanilla Apply function for operator. The only possible way is re-run this operator.
|
||||||
|
# However the experience is pretty shit. Because the window still locate at the left-bottom corner.
|
||||||
|
# User can't keep up to change it.
|
||||||
|
#
|
||||||
|
# We use a dirty way to implement Apply function. The solution is pretty like BME struct adder.
|
||||||
|
# We use a CollectionProperty to store all align steps.
|
||||||
|
# And use a BoolProperty with update function to implement Apply button. Once its value changed,
|
||||||
|
# reset its value (order a recursive hinder), and add a new settings.
|
||||||
|
|
||||||
|
class BBP_PG_legacy_align_history(bpy.types.PropertyGroup):
|
||||||
|
align_x: bpy.props.BoolProperty(
|
||||||
|
name = "X Position",
|
||||||
|
default = False,
|
||||||
|
)
|
||||||
|
align_y: bpy.props.BoolProperty(
|
||||||
|
name = "Y Position",
|
||||||
|
default = False,
|
||||||
|
)
|
||||||
|
align_z: bpy.props.BoolProperty(
|
||||||
|
name = "Z Position",
|
||||||
|
default = False,
|
||||||
|
)
|
||||||
|
current_align_mode: bpy.props.EnumProperty(
|
||||||
|
name = "Current Object (Active Object)",
|
||||||
|
items = _g_EnumHelper_AlignMode.generate_items(),
|
||||||
|
default = _g_EnumHelper_AlignMode.to_selection(AlignMode.AxisCenter),
|
||||||
|
)
|
||||||
|
target_align_mode: bpy.props.EnumProperty(
|
||||||
|
name = "Target Objects (Other Objects)",
|
||||||
|
items = _g_EnumHelper_AlignMode.generate_items(),
|
||||||
|
default = _g_EnumHelper_AlignMode.to_selection(AlignMode.AxisCenter),
|
||||||
|
)
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
class BBP_OT_legacy_align(bpy.types.Operator):
|
||||||
|
"""Align Objects with 3ds Max Style"""
|
||||||
|
bl_idname = "bbp.legacy_align"
|
||||||
|
bl_label = "3ds Max Align"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
# the updator for apply flag value
|
||||||
|
def apply_flag_updated(self, context):
|
||||||
|
# check hinder and set hinder first
|
||||||
|
if self.recursive_hinder: return
|
||||||
|
self.recursive_hinder = True
|
||||||
|
|
||||||
|
# reset apply button value (default is True)
|
||||||
|
# due to the hinder, no recursive calling will happend
|
||||||
|
if self.apply_flag == True: return
|
||||||
|
self.apply_flag = True
|
||||||
|
|
||||||
|
# add a new entry in history
|
||||||
|
self.align_history.add()
|
||||||
|
|
||||||
|
# reset hinder
|
||||||
|
self.recursive_hinder = False
|
||||||
|
# blender required
|
||||||
|
return None
|
||||||
|
|
||||||
|
apply_flag: bpy.props.BoolProperty(
|
||||||
|
name = "Apply Flag",
|
||||||
|
description = "Internal flag.",
|
||||||
|
options = {'HIDDEN', 'SKIP_SAVE'},
|
||||||
|
default = True, # default True value to make it as a "light" button, not a grey one.
|
||||||
|
update = apply_flag_updated,
|
||||||
|
)
|
||||||
|
recursive_hinder: bpy.props.BoolProperty(
|
||||||
|
name = "Recursive Hinder",
|
||||||
|
description = "An internal flag to prevent the loop calling to apply_flags's updator.",
|
||||||
|
options = {'HIDDEN', 'SKIP_SAVE'},
|
||||||
|
default = False,
|
||||||
|
)
|
||||||
|
align_history : bpy.props.CollectionProperty(
|
||||||
|
name = "Historys",
|
||||||
|
description = "Align history.",
|
||||||
|
type = BBP_PG_legacy_align_history,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(self, context):
|
||||||
|
return _check_align_requirement()
|
||||||
|
|
||||||
|
def invoke(self, context, event):
|
||||||
|
# clear history and add 1 entry for following functions
|
||||||
|
self.align_history.clear()
|
||||||
|
self.align_history.add()
|
||||||
|
# run execute() function
|
||||||
|
return self.execute(context)
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
# get processed objects
|
||||||
|
(current_obj, target_objs) = _prepare_objects()
|
||||||
|
# iterate history to align objects
|
||||||
|
entry: BBP_PG_legacy_align_history
|
||||||
|
for entry in self.align_history:
|
||||||
|
_align_objects(
|
||||||
|
current_obj, target_objs,
|
||||||
|
entry.align_x, entry.align_y, entry.align_z,
|
||||||
|
_g_EnumHelper_AlignMode.get_selection(entry.current_align_mode),
|
||||||
|
_g_EnumHelper_AlignMode.get_selection(entry.target_align_mode)
|
||||||
|
)
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
# get last entry in history to show
|
||||||
|
entry: BBP_PG_legacy_align_history = self.align_history[-1]
|
||||||
|
|
||||||
|
layout = self.layout
|
||||||
|
col = layout.column()
|
||||||
|
|
||||||
|
# show axis
|
||||||
|
col.label(text="Align Axis")
|
||||||
|
row = col.row()
|
||||||
|
row.prop(entry, "align_x", toggle = 1)
|
||||||
|
row.prop(entry, "align_y", toggle = 1)
|
||||||
|
row.prop(entry, "align_z", toggle = 1)
|
||||||
|
|
||||||
|
# show mode
|
||||||
|
col.separator()
|
||||||
|
col.label(text = 'Current Object (Active Object)')
|
||||||
|
col.prop(entry, "current_align_mode", expand = True)
|
||||||
|
col.label(text = 'Target Objects (Other Objects)')
|
||||||
|
col.prop(entry, "target_align_mode", expand = True)
|
||||||
|
|
||||||
|
# show apply button
|
||||||
|
col.separator()
|
||||||
|
col.prop(self, 'apply_flag', text = 'Apply', icon = 'CHECKMARK', toggle = 1)
|
||||||
|
|
||||||
|
#region Core Functions
|
||||||
|
|
||||||
|
def _check_align_requirement() -> bool:
|
||||||
|
# check current obj
|
||||||
|
if bpy.context.active_object is None:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# check target obj with filter of current obj
|
||||||
|
length = len(bpy.context.selected_objects)
|
||||||
|
if bpy.context.active_object in bpy.context.selected_objects:
|
||||||
|
length -= 1
|
||||||
|
return length != 0
|
||||||
|
|
||||||
|
def _prepare_objects() -> tuple[bpy.types.Object, set[bpy.types.Object]]:
|
||||||
|
# get current object
|
||||||
|
current_obj: bpy.types.Object = bpy.context.active_object
|
||||||
|
|
||||||
|
# get target objects
|
||||||
|
target_objs: set[bpy.types.Object] = set(bpy.context.selected_objects)
|
||||||
|
# remove active one
|
||||||
|
if current_obj in target_objs:
|
||||||
|
target_objs.remove(current_obj)
|
||||||
|
|
||||||
|
# return value
|
||||||
|
return (current_obj, target_objs)
|
||||||
|
|
||||||
|
def _align_objects(
|
||||||
|
current_obj: bpy.types.Object, target_objs: set[bpy.types.Object],
|
||||||
|
align_x: bool, align_y: bool, align_z: bool, current_mode: AlignMode, target_mode: AlignMode) -> None:
|
||||||
|
# if no align, skip
|
||||||
|
if not (align_x or align_y or align_z):
|
||||||
|
return
|
||||||
|
|
||||||
|
# calc current object data
|
||||||
|
current_obj_bbox: tuple[mathutils.Vector] = tuple(current_obj.matrix_world @ mathutils.Vector(corner) for corner in current_obj.bound_box)
|
||||||
|
current_obj_ref: mathutils.Vector = _get_object_ref_point(current_obj, current_obj_bbox, current_mode)
|
||||||
|
|
||||||
|
# process each target obj
|
||||||
|
for target_obj in target_objs:
|
||||||
|
# calc target object data
|
||||||
|
target_obj_bbox: tuple[mathutils.Vector] = tuple(target_obj.matrix_world @ mathutils.Vector(corner) for corner in target_obj.bound_box)
|
||||||
|
target_obj_ref: mathutils.Vector = _get_object_ref_point(target_obj, target_obj_bbox, target_mode)
|
||||||
|
# do align
|
||||||
|
if align_x:
|
||||||
|
target_obj.location.x += current_obj_ref.x - target_obj_ref.x
|
||||||
|
if align_y:
|
||||||
|
target_obj.location.y += current_obj_ref.y - target_obj_ref.y
|
||||||
|
if align_z:
|
||||||
|
target_obj.location.z += current_obj_ref.z - target_obj_ref.z
|
||||||
|
|
||||||
|
def _get_object_ref_point(obj: bpy.types.Object, corners: tuple[mathutils.Vector], mode: AlignMode) -> mathutils.Vector:
|
||||||
|
ref_pos: mathutils.Vector = mathutils.Vector((0, 0, 0))
|
||||||
|
|
||||||
|
match(mode):
|
||||||
|
case AlignMode.Min:
|
||||||
|
ref_pos.x = min((vec.x for vec in corners))
|
||||||
|
ref_pos.y = min((vec.y for vec in corners))
|
||||||
|
ref_pos.z = min((vec.z for vec in corners))
|
||||||
|
case AlignMode.Max:
|
||||||
|
ref_pos.x = max((vec.x for vec in corners))
|
||||||
|
ref_pos.y = max((vec.y for vec in corners))
|
||||||
|
ref_pos.z = max((vec.z for vec in corners))
|
||||||
|
case AlignMode.BBoxCenter:
|
||||||
|
max_vec_cache: mathutils.Vector = mathutils.Vector((0, 0, 0))
|
||||||
|
min_vec_cache: mathutils.Vector = mathutils.Vector((0, 0, 0))
|
||||||
|
|
||||||
|
min_vec_cache.x = min((vec.x for vec in corners))
|
||||||
|
min_vec_cache.y = min((vec.y for vec in corners))
|
||||||
|
min_vec_cache.z = min((vec.z for vec in corners))
|
||||||
|
max_vec_cache.x = max((vec.x for vec in corners))
|
||||||
|
max_vec_cache.y = max((vec.y for vec in corners))
|
||||||
|
max_vec_cache.z = max((vec.z for vec in corners))
|
||||||
|
|
||||||
|
ref_pos.x = (max_vec_cache.x + min_vec_cache.x) / 2
|
||||||
|
ref_pos.y = (max_vec_cache.y + min_vec_cache.y) / 2
|
||||||
|
ref_pos.z = (max_vec_cache.z + min_vec_cache.z) / 2
|
||||||
|
case AlignMode.AxisCenter:
|
||||||
|
ref_pos.x = obj.location.x
|
||||||
|
ref_pos.y = obj.location.y
|
||||||
|
ref_pos.z = obj.location.z
|
||||||
|
case _:
|
||||||
|
raise UTIL_functions.BBPException('inpossible align mode.')
|
||||||
|
|
||||||
|
return ref_pos
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
def register():
|
||||||
|
bpy.utils.register_class(BBP_PG_legacy_align_history)
|
||||||
|
bpy.utils.register_class(BBP_OT_legacy_align)
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.utils.unregister_class(BBP_OT_legacy_align)
|
||||||
|
bpy.utils.unregister_class(BBP_PG_legacy_align_history)
|
@ -33,6 +33,8 @@ TOKEN_SHOWCASE_CFGS_TITLE: str = 'title'
|
|||||||
TOKEN_SHOWCASE_CFGS_DESC: str = 'desc'
|
TOKEN_SHOWCASE_CFGS_DESC: str = 'desc'
|
||||||
TOKEN_SHOWCASE_CFGS_DEFAULT: str = 'default'
|
TOKEN_SHOWCASE_CFGS_DEFAULT: str = 'default'
|
||||||
|
|
||||||
|
TOKEN_SKIP: str = 'skip'
|
||||||
|
|
||||||
TOKEN_PARAMS: str = 'params'
|
TOKEN_PARAMS: str = 'params'
|
||||||
TOKEN_PARAMS_FIELD: str = 'field'
|
TOKEN_PARAMS_FIELD: str = 'field'
|
||||||
TOKEN_PARAMS_DATA: str = 'data'
|
TOKEN_PARAMS_DATA: str = 'data'
|
||||||
@ -127,6 +129,9 @@ def _eval_showcase_cfgs_default(strl: str) -> typing.Any:
|
|||||||
def _eval_params(strl: str, cfgs_data: dict[str, typing.Any]) -> typing.Any:
|
def _eval_params(strl: str, cfgs_data: dict[str, typing.Any]) -> typing.Any:
|
||||||
return eval(strl, _g_ProgFieldGlobals, cfgs_data)
|
return eval(strl, _g_ProgFieldGlobals, cfgs_data)
|
||||||
|
|
||||||
|
def _eval_skip(strl: str, params_data: dict[str, typing.Any]) -> typing.Any:
|
||||||
|
return eval(strl, _g_ProgFieldGlobals, params_data)
|
||||||
|
|
||||||
def _eval_vars(strl: str, params_data: dict[str, typing.Any]) -> typing.Any:
|
def _eval_vars(strl: str, params_data: dict[str, typing.Any]) -> typing.Any:
|
||||||
return eval(strl, _g_ProgFieldGlobals, params_data)
|
return eval(strl, _g_ProgFieldGlobals, params_data)
|
||||||
|
|
||||||
@ -272,6 +277,10 @@ def create_bme_struct(
|
|||||||
# get prototype first
|
# get prototype first
|
||||||
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
proto: dict[str, typing.Any] = _get_prototype_by_identifier(ident)
|
||||||
|
|
||||||
|
# check whether skip the whole struct before cal vars
|
||||||
|
if _eval_skip(proto[TOKEN_SKIP], params) == True:
|
||||||
|
return
|
||||||
|
|
||||||
# calc vars by given params
|
# calc vars by given params
|
||||||
# please note i will add entries directly into params dict
|
# please note i will add entries directly into params dict
|
||||||
# but the params dict will not used independently later,
|
# but the params dict will not used independently later,
|
||||||
@ -307,20 +316,34 @@ def create_bme_struct(
|
|||||||
# prepare mesh part data
|
# prepare mesh part data
|
||||||
mesh_part: UTIL_blender_mesh.MeshWriterIngredient = UTIL_blender_mesh.MeshWriterIngredient()
|
mesh_part: UTIL_blender_mesh.MeshWriterIngredient = UTIL_blender_mesh.MeshWriterIngredient()
|
||||||
def vpos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
def vpos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
||||||
|
bv: mathutils.Vector = mathutils.Vector((0, 0, 0))
|
||||||
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
||||||
for vec_idx in valid_vec_idx:
|
for vec_idx in valid_vec_idx:
|
||||||
# BME no need to convert co system
|
# BME no need to convert co system
|
||||||
v.x, v.y, v.z = _eval_others(proto[TOKEN_VERTICES][vec_idx][TOKEN_VERTICES_DATA], params)
|
# but it need mul with transform matrix
|
||||||
|
bv.x, bv.y, bv.z = _eval_others(proto[TOKEN_VERTICES][vec_idx][TOKEN_VERTICES_DATA], params)
|
||||||
|
bv = transform @ bv
|
||||||
|
# yield result
|
||||||
|
v.x, v.y, v.z = bv.x, bv.y, bv.z
|
||||||
yield v
|
yield v
|
||||||
mesh_part.mVertexPosition = vpos_iterator()
|
mesh_part.mVertexPosition = vpos_iterator()
|
||||||
def vnml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
def vnml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
|
||||||
|
# calc normal used transform first
|
||||||
|
# ref: https://zhuanlan.zhihu.com/p/96717729
|
||||||
|
nml_transform: mathutils.Matrix = transform.inverted_safe().transposed()
|
||||||
|
# prepare vars
|
||||||
|
bv: mathutils.Vector = mathutils.Vector((0, 0, 0))
|
||||||
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
|
||||||
for face_idx in valid_face_idx:
|
for face_idx in valid_face_idx:
|
||||||
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
||||||
for i in range(len(face_data[TOKEN_FACES_INDICES])):
|
for i in range(len(face_data[TOKEN_FACES_INDICES])):
|
||||||
v.x, v.y, v.z = _eval_others(face_data[TOKEN_FACES_NORMALS][i], params)
|
# BME normals need transform by matrix first,
|
||||||
# BME normals need normalize
|
bv.x, bv.y, bv.z = _eval_others(face_data[TOKEN_FACES_NORMALS][i], params)
|
||||||
UTIL_virtools_types.vxvector3_normalize(v)
|
bv = nml_transform @ bv
|
||||||
|
# then normalize it
|
||||||
|
bv.normalize()
|
||||||
|
# yield result
|
||||||
|
v.x, v.y, v.z = bv.x, bv.y, bv.z
|
||||||
yield v
|
yield v
|
||||||
mesh_part.mVertexNormal = vnml_iterator()
|
mesh_part.mVertexNormal = vnml_iterator()
|
||||||
def vuv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]:
|
def vuv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]:
|
||||||
@ -328,6 +351,7 @@ def create_bme_struct(
|
|||||||
for face_idx in valid_face_idx:
|
for face_idx in valid_face_idx:
|
||||||
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
face_data: dict[str, typing.Any] = proto[TOKEN_FACES][face_idx]
|
||||||
for i in range(len(face_data[TOKEN_FACES_INDICES])):
|
for i in range(len(face_data[TOKEN_FACES_INDICES])):
|
||||||
|
# BME uv do not need any extra process
|
||||||
v.x, v.y = _eval_others(face_data[TOKEN_FACES_UVS][i], params)
|
v.x, v.y = _eval_others(face_data[TOKEN_FACES_UVS][i], params)
|
||||||
yield v
|
yield v
|
||||||
mesh_part.mVertexUV = vuv_iterator()
|
mesh_part.mVertexUV = vuv_iterator()
|
||||||
@ -390,7 +414,7 @@ def create_bme_struct(
|
|||||||
proto_instance[TOKEN_INSTANCES_IDENTIFIER],
|
proto_instance[TOKEN_INSTANCES_IDENTIFIER],
|
||||||
writer,
|
writer,
|
||||||
bmemtl,
|
bmemtl,
|
||||||
_eval_others(proto_instance[TOKEN_INSTANCES_TRANSFORM], params),
|
transform @ _eval_others(proto_instance[TOKEN_INSTANCES_TRANSFORM], params),
|
||||||
instance_params
|
instance_params
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -27,14 +27,6 @@ def vxvector3_conv_co(self: VxVector3) -> None:
|
|||||||
"""
|
"""
|
||||||
self.y, self.z = self.z, self.y
|
self.y, self.z = self.z, self.y
|
||||||
|
|
||||||
def vxvector3_normalize(self: VxVector3) -> None:
|
|
||||||
"""
|
|
||||||
Normalize given Vector
|
|
||||||
"""
|
|
||||||
cache: mathutils.Vector = mathutils.Vector((self.x, self.y, self.z))
|
|
||||||
cache.normalize()
|
|
||||||
self.x, self.y, self.z = cache.x, cache.y, cache.z
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region VxMatrix Patch
|
#region VxMatrix Patch
|
||||||
|
@ -33,13 +33,14 @@ from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, P
|
|||||||
from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools
|
from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools
|
||||||
from . import OP_UV_flatten_uv, OP_UV_rail_uv
|
from . import OP_UV_flatten_uv, OP_UV_rail_uv
|
||||||
from . import OP_ADDS_component, OP_ADDS_bme
|
from . import OP_ADDS_component, OP_ADDS_bme
|
||||||
|
from . import OP_OBJECT_legacy_align
|
||||||
|
|
||||||
#region Menu
|
#region Menu
|
||||||
|
|
||||||
# ===== Menu Defines =====
|
# ===== Menu Defines =====
|
||||||
|
|
||||||
class BBP_MT_View3DMenu(bpy.types.Menu):
|
class BBP_MT_View3DMenu(bpy.types.Menu):
|
||||||
"""Ballance 3D operators"""
|
"""Ballance 3D Operators"""
|
||||||
bl_idname = "BBP_MT_View3DMenu"
|
bl_idname = "BBP_MT_View3DMenu"
|
||||||
bl_label = "Ballance"
|
bl_label = "Ballance"
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ class BBP_MT_View3DMenu(bpy.types.Menu):
|
|||||||
layout = self.layout
|
layout = self.layout
|
||||||
layout.operator(OP_UV_flatten_uv.BBP_OT_flatten_uv.bl_idname)
|
layout.operator(OP_UV_flatten_uv.BBP_OT_flatten_uv.bl_idname)
|
||||||
layout.operator(OP_UV_rail_uv.BBP_OT_rail_uv.bl_idname)
|
layout.operator(OP_UV_rail_uv.BBP_OT_rail_uv.bl_idname)
|
||||||
|
layout.operator(OP_OBJECT_legacy_align.BBP_OT_legacy_align.bl_idname)
|
||||||
|
|
||||||
class BBP_MT_AddBmeMenu(bpy.types.Menu):
|
class BBP_MT_AddBmeMenu(bpy.types.Menu):
|
||||||
"""Add Ballance Floor"""
|
"""Add Ballance Floor"""
|
||||||
@ -163,6 +165,8 @@ def register() -> None:
|
|||||||
OP_ADDS_component.register()
|
OP_ADDS_component.register()
|
||||||
OP_ADDS_bme.register()
|
OP_ADDS_bme.register()
|
||||||
|
|
||||||
|
OP_OBJECT_legacy_align.register()
|
||||||
|
|
||||||
# register other classes
|
# register other classes
|
||||||
for cls in g_BldClasses:
|
for cls in g_BldClasses:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
@ -184,6 +188,8 @@ def unregister() -> None:
|
|||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|
||||||
# unregister modules
|
# unregister modules
|
||||||
|
OP_OBJECT_legacy_align.unregister()
|
||||||
|
|
||||||
OP_ADDS_bme.unregister()
|
OP_ADDS_bme.unregister()
|
||||||
OP_ADDS_component.unregister()
|
OP_ADDS_component.unregister()
|
||||||
OP_UV_flatten_uv.unregister()
|
OP_UV_flatten_uv.unregister()
|
||||||
|
Loading…
Reference in New Issue
Block a user