From e153e51abd2fc0c7dcee27c6a916f61a857d819d Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Mon, 30 Jan 2023 22:49:49 +0800 Subject: [PATCH] [feat] improve element adder - fix ambiguous default side setter for floor adder. use "update" field of EnumProperty instead. also applied for dup element with span adder. - divide component adder into 3 different adder, to process different add strategies. - update elements placeholder adder. this change will force all element placeholder share a single mesh in the whole map. - add series element adder. --- .../OBJS_add_components.py | 221 ++++++++++++++---- ballance_blender_plugin/OBJS_add_floors.py | 39 ++-- ballance_blender_plugin/UTILS_functions.py | 22 +- ballance_blender_plugin/__init__.py | 7 + 4 files changed, 216 insertions(+), 73 deletions(-) diff --git a/ballance_blender_plugin/OBJS_add_components.py b/ballance_blender_plugin/OBJS_add_components.py index 906eb40..55761a0 100644 --- a/ballance_blender_plugin/OBJS_add_components.py +++ b/ballance_blender_plugin/OBJS_add_components.py @@ -1,12 +1,34 @@ import bpy, mathutils 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( @@ -20,52 +42,17 @@ class BALLANCE_OT_add_components(bpy.types.Operator): ), ) - attentionElements = ("PC_TwoFlames", "PR_Resetpoint") - uniqueElements = ("PS_FourFlames", "PE_Balloon") - canDuplicatedElements = ('P_Extra_Point', 'P_Modul_18', 'P_Modul_26') - - elements_sector: bpy.props.IntProperty( - name="Sector", - description="Define which sector the object will be grouped in", - min=1, max=8, - default=1, - ) - - elements_duplicated: bpy.props.BoolProperty( - name="Duplicated", - description="Whether duplicate elements (Nong xxx / 脓xxx)", - default=False, - ) - elements_dup_times: bpy.props.IntProperty( - name="Duplication Times", - description="How many this element should be duplicated.", - min=1, max=64, - soft_min=1, soft_max=32, - default=1, - ) - def execute(self, context): # get name - if self.elements_type in self.uniqueElements: - finalObjectName = self.elements_type + "_01" - elif self.elements_type in self.attentionElements: - finalObjectName = self.elements_type + "_0" + str(self.elements_sector) - else: - finalObjectName = self.elements_type + "_0" + str(self.elements_sector) + "_" + finalObjectName = self.get_component_name(self.elements_type) # create object loadedMesh = UTILS_functions.load_component( - UTILS_constants.bmfile_componentList.index(self.elements_type)) + UTILS_constants.bmfile_componentList.index(self.elements_type) + ) obj = bpy.data.objects.new(finalObjectName, loadedMesh) UTILS_functions.add_into_scene_and_move_to_cursor(obj) - # extra duplication - if (self.elements_type in self.canDuplicatedElements) and self.elements_duplicated: - for i in range(self.elements_dup_times - 1): - obj = bpy.data.objects.new(finalObjectName, loadedMesh) - UTILS_functions.add_into_scene_and_move_to_cursor(obj) - - return {'FINISHED'} def invoke(self, context, event): @@ -76,16 +63,148 @@ class BALLANCE_OT_add_components(bpy.types.Operator): layout = self.layout # attension notice if self.elements_type in self.attentionElements: - layout.label(text="Please note that sector is suffix.") - if self.elements_type in self.canDuplicatedElements: - layout.label(text="This element can use duplication feature.") + layout.label(text="NOTE: Check Sector ID carefully.") + if self.elements_type in self.uniqueElements: + layout.label(text="NOTE: This element have unique name.") # cfg layout.prop(self, "elements_type") - if self.elements_type not in self.uniqueElements: - layout.prop(self, "elements_sector") + self.parent_draw(layout, self.elements_type) - if self.elements_type in self.canDuplicatedElements: - layout.separator() - layout.prop(self, "elements_duplicated") - layout.prop(self, "elements_dup_times") + + +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'} + + 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( + ('P_Extra_Point', 'P_Modul_18', 'P_Modul_26') + ) + ), + ) + + elements_dup_times: bpy.props.IntProperty( + name="Duplication Count", + description="How many this element should be duplicated.", + min=2, max=64, + soft_min=2, soft_max=32, + default=2, + ) + + def execute(self, context): + # get name + finalObjectName = self.get_component_name(self.elements_type) + + # load mesh + loadedMesh = UTILS_functions.load_component( + UTILS_constants.bmfile_componentList.index(self.elements_type) + ) + # create object + for i in range(self.elements_dup_times): + obj = bpy.data.objects.new(finalObjectName, loadedMesh) + UTILS_functions.add_into_scene_and_move_to_cursor(obj) + + return {'FINISHED'} + + def invoke(self, context, event): + wm = context.window_manager + return wm.invoke_props_dialog(self) + + def draw(self, context): + layout = self.layout + layout.prop(self, "elements_type") + self.parent_draw(layout, self.elements_type) + layout.prop(self, "elements_dup_times") + + + +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") diff --git a/ballance_blender_plugin/OBJS_add_floors.py b/ballance_blender_plugin/OBJS_add_floors.py index fe18870..3d4dc7a 100644 --- a/ballance_blender_plugin/OBJS_add_floors.py +++ b/ballance_blender_plugin/OBJS_add_floors.py @@ -12,6 +12,23 @@ class BALLANCE_OT_add_floors(bpy.types.Operator): bl_label = "Add floor" 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", @@ -25,7 +42,7 @@ class BALLANCE_OT_add_floors(bpy.types.Operator): (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( @@ -74,8 +91,6 @@ class BALLANCE_OT_add_floors(bpy.types.Operator): default=True ) - previous_floor_type = '' - @classmethod def poll(self, context): prefs = bpy.context.preferences.addons[__package__].preferences @@ -130,27 +145,15 @@ class BALLANCE_OT_add_floors(bpy.types.Operator): UTILS_functions.add_into_scene_and_move_to_cursor(obj) return {'FINISHED'} - def invoke(self, context, event): # yyc marked. Blumia reported. # prepare settings before registing # otherwise the mesh will not be created when first run. # (do not change any properties) - # 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'] + # yyc marked again. + # now I migrate default side value setter to updator of enum property. + # nothing need to process in here now. return self.execute(context) diff --git a/ballance_blender_plugin/UTILS_functions.py b/ballance_blender_plugin/UTILS_functions.py index c913bb6..040b893 100644 --- a/ballance_blender_plugin/UTILS_functions.py +++ b/ballance_blender_plugin/UTILS_functions.py @@ -116,8 +116,21 @@ def parse_material_nodes(mtl): # load component def load_component(component_id): - # get file first + # get component name from id component_name = UTILS_constants.bmfile_componentList[component_id] + + # create real mesh. + # if component mesh is existed, use existed one. + (mesh, skip_init) = create_instance_with_option( + UTILS_constants.BmfileInfoType.MESH, + "BlcBldPlg_EleMesh_" + component_name, + 'CURRENT' + ) + if skip_init: + return mesh + + # mesh is not existing. start to load mesh + # get file first selected_file = os.path.join( os.path.dirname(__file__), 'meshes', @@ -126,9 +139,6 @@ def load_component(component_id): # read file. please note this sector is sync with import_bm's mesh's code. when something change, please change each other. fmesh = open(selected_file, 'rb') - - # create real mesh, we don't need to consider name. blender will solve duplicated name - mesh = bpy.data.meshes.new('mesh_' + component_name) vList = [] vnList = [] @@ -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(): diff --git a/ballance_blender_plugin/__init__.py b/ballance_blender_plugin/__init__.py index 12e1935..baf65c2 100644 --- a/ballance_blender_plugin/__init__.py +++ b/ballance_blender_plugin/__init__.py @@ -127,11 +127,16 @@ class BALLANCE_MT_AddElementsMenu(bpy.types.Menu): def draw(self, context): layout = self.layout + layout.label(text="Basic Elements") for item in UTILS_constants.bmfile_componentList: cop = layout.operator( OBJS_add_components.BALLANCE_OT_add_components.bl_idname, text=item, icon_value = UTILS_icons_manager.get_element_icon(item)) cop.elements_type = item + + layout.label(text="Special Elements") + layout.operator(OBJS_add_components.BALLANCE_OT_add_components_dup.bl_idname, text="Dup Elements") + layout.operator(OBJS_add_components.BALLANCE_OT_add_components_series.bl_idname, text="Elements Series") # ============================================= # blender call system @@ -149,6 +154,8 @@ 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,