From f10a9f0b5c749c7fc04d61560c8d81a8bfafdae6 Mon Sep 17 00:00:00 2001 From: kreezii Date: Sun, 18 Oct 2020 19:07:33 +0200 Subject: [PATCH 1/7] Datafiles path, apply modifier for 2.9. undo_push on dragonbones export --- Blender/coa_tools/__init__.py | 6 +++--- .../operators/exporter/export_dragonbones.py | 15 ++++++++------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/Blender/coa_tools/__init__.py b/Blender/coa_tools/__init__.py index d4abf19..2ae861c 100644 --- a/Blender/coa_tools/__init__.py +++ b/Blender/coa_tools/__init__.py @@ -76,7 +76,7 @@ from . operators.exporter import export_creature # register -################################## +################################## import traceback @@ -341,7 +341,7 @@ def update_properties(scene, depsgraph): context = bpy.context for obj in bpy.data.objects: obj_eval = obj.evaluated_get(depsgraph) - + if obj_eval.coa_tools.slot_index != obj_eval.coa_tools.slot_index_last: change_slot_mesh_data(bpy.context, obj, obj_eval) obj.coa_tools.slot_index_last = obj_eval.coa_tools.slot_index @@ -370,7 +370,7 @@ def copy_icons(): for icon_name in icons: icon_path = os.path.join(bpy.utils.user_resource("SCRIPTS", "addons"), "coa_tools", "icons", icon_name) - b_icon_path = os.path.join(os.path.dirname(bpy.app.binary_path), version, "datafiles", "icons", icon_name) + b_icon_path = os.path.join(bpy.utils.user_resource("DATAFILES"), version, "datafiles", "icons", icon_name) if os.path.isfile(b_icon_path): try: diff --git a/Blender/coa_tools/operators/exporter/export_dragonbones.py b/Blender/coa_tools/operators/exporter/export_dragonbones.py index a9e9807..254ac1d 100644 --- a/Blender/coa_tools/operators/exporter/export_dragonbones.py +++ b/Blender/coa_tools/operators/exporter/export_dragonbones.py @@ -745,7 +745,7 @@ def get_bone_data(self,armature,sprite_object,scale): data["transform"]["x"] = round(pos[0], 2) data["transform"]["y"] = round(pos[1], 2) - ### get bone angle + ### get bone angle angle = get_bone_angle(armature,bone) if not bone_uses_constraints[pbone.name] else get_bone_angle(armature,bone,relative=False) bone_default_rot[bone.name] = angle if angle != 0: @@ -817,7 +817,7 @@ def get_bone_weight_data(self,obj,armature): return data, bones ### Export Animations -### get objs and bones that are keyed on given frame +### get objs and bones that are keyed on given frame def bone_key_on_frame(bone,frame,animation_data,type="LOCATION"): ### LOCATION, ROTATION, SCALE, ANY action = animation_data.action if animation_data != None else None type = "."+type.lower() @@ -907,7 +907,7 @@ def get_animation_data(self,sprite_object,armature,armature_orig): ffd_keyframe_duration[slot2.mesh.name] = {"ffd_duration":0} ffd_last_frame_values[slot2.mesh.name] = None - ### check if slot has animation data. if so, store for later usage + ### check if slot has animation data. if so, store for later usage SHAPEKEY_ANIMATION = {} for i in range(anim.frame_end+1): frame = anim.frame_end-i @@ -1324,6 +1324,7 @@ def execute(self, context): self.scene.coa_tools.nla_mode = coa_nla_mode self.report({"INFO"},"Export successful.") + bpy.ops.ed.undo_push(message="Export DragonBones") bpy.ops.ed.undo() return {"FINISHED"} @@ -1392,7 +1393,7 @@ def generate_texture_atlas(self, sprites, atlas_name, img_path, img_width=512, i for obj in context.scene.objects: obj.select_set(False) - ### get a list of all sprites and containing slots + ### get a list of all sprites and containing slots slots = [] for sprite in sprites: if sprite.type == "MESH": @@ -1425,7 +1426,7 @@ def generate_texture_atlas(self, sprites, atlas_name, img_path, img_width=512, i override = bpy.context.copy() override["object"] = dupli_sprite override["active_object"] = dupli_sprite - bpy.ops.object.modifier_apply(override, apply_as="DATA", modifier=modifier.name) + bpy.ops.object.modifier_apply() # for Blender 2.9X for modifier in dupli_sprite.modifiers: dupli_sprite.modifiers.remove(modifier) @@ -1433,7 +1434,7 @@ def generate_texture_atlas(self, sprites, atlas_name, img_path, img_width=512, i for group in dupli_sprite.vertex_groups: dupli_sprite.vertex_groups.remove(group) - ### assign mesh as vertex group + ### assign mesh as vertex group dupli_sprite.vertex_groups.new(name=slot["slot"].name) bpy.ops.object.mode_set(mode="EDIT") bpy.ops.mesh.reveal() @@ -1548,4 +1549,4 @@ def generate_texture_atlas(self, sprites, atlas_name, img_path, img_width=512, i context.scene.render.image_settings.compression = compression_rate - bpy.data.objects.remove(tex_atlas_obj, do_unlink=True) \ No newline at end of file + bpy.data.objects.remove(tex_atlas_obj, do_unlink=True) From 5b19fc525eca7504e5a7dc6a03e9526bf07ad177 Mon Sep 17 00:00:00 2001 From: kreezii Date: Sun, 18 Oct 2020 19:18:11 +0200 Subject: [PATCH 2/7] modifier_apply update --- Blender/coa_tools/operators/exporter/export_dragonbones.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Blender/coa_tools/operators/exporter/export_dragonbones.py b/Blender/coa_tools/operators/exporter/export_dragonbones.py index 254ac1d..1f19143 100644 --- a/Blender/coa_tools/operators/exporter/export_dragonbones.py +++ b/Blender/coa_tools/operators/exporter/export_dragonbones.py @@ -1426,7 +1426,7 @@ def generate_texture_atlas(self, sprites, atlas_name, img_path, img_width=512, i override = bpy.context.copy() override["object"] = dupli_sprite override["active_object"] = dupli_sprite - bpy.ops.object.modifier_apply() # for Blender 2.9X + bpy.ops.object.modifier_apply(modifier=modifier.name) # for Blender 2.9X for modifier in dupli_sprite.modifiers: dupli_sprite.modifiers.remove(modifier) From cb257868fa5a226f75240ec73bddf140fa0dfafa Mon Sep 17 00:00:00 2001 From: kreezii Date: Mon, 19 Oct 2020 09:44:56 +0200 Subject: [PATCH 3/7] Fix datafiles path --- Blender/coa_tools/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Blender/coa_tools/__init__.py b/Blender/coa_tools/__init__.py index 2ae861c..d79c511 100644 --- a/Blender/coa_tools/__init__.py +++ b/Blender/coa_tools/__init__.py @@ -370,7 +370,7 @@ def copy_icons(): for icon_name in icons: icon_path = os.path.join(bpy.utils.user_resource("SCRIPTS", "addons"), "coa_tools", "icons", icon_name) - b_icon_path = os.path.join(bpy.utils.user_resource("DATAFILES"), version, "datafiles", "icons", icon_name) + b_icon_path = os.path.join(bpy.utils.user_resource("DATAFILES"), "icons", icon_name) if os.path.isfile(b_icon_path): try: From a858dcd958d0fef7415c358bcde43ed8666a641d Mon Sep 17 00:00:00 2001 From: kreezii Date: Sat, 24 Oct 2020 21:45:04 +0200 Subject: [PATCH 4/7] COA Export Collection fix. Option to modify DragonBones armature name. --- .../coa_tools/operators/exporter/export_dragonbones.py | 9 +++++++++ .../operators/exporter/texture_atlas_generator.py | 8 +++++--- Blender/coa_tools/properties.py | 2 ++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Blender/coa_tools/operators/exporter/export_dragonbones.py b/Blender/coa_tools/operators/exporter/export_dragonbones.py index 1f19143..24e20f1 100644 --- a/Blender/coa_tools/operators/exporter/export_dragonbones.py +++ b/Blender/coa_tools/operators/exporter/export_dragonbones.py @@ -1289,6 +1289,10 @@ def execute(self, context): self.json_data = setup_json_project(self.scene.coa_tools.project_name) ### create base template self.json_data["armature"] = [setup_armature_data(self.sprite_object)] ### create base armature + if self.scene.coa_tools.armature_change: + self.json_data["armature"][0]["name"] = self.scene.coa_tools.armature_name; + else: + self.json_data["armature"][0]["name"] = self.scene.coa_tools.project_name; self.json_data["armature"][0]["frameRate"] = self.scene.render.fps self.json_data["armature"][0]["slot"] = get_slot_data(self,self.sprites) self.json_data["armature"][0]["skin"] = get_skin_data(self,self.sprites,self.armature,self.scale) @@ -1366,7 +1370,12 @@ def draw(self, context): box_col.label(text="Data Settings:") subrow = box_col.row(align=True) + subrowbis = box_col.row(align=True) if self.scene.coa_tools.runtime_format == "DRAGONBONES": + subrowbis.prop(self.scene.coa_tools, "armature_change") + if self.scene.coa_tools.armature_change: + subrowbis.prop(self.scene.coa_tools, "armature_name", text="") + subrow.prop(self.scene.coa_tools, "export_bake_anim") if self.scene.coa_tools.export_bake_anim: subrow.prop(self.scene.coa_tools, "export_bake_steps") diff --git a/Blender/coa_tools/operators/exporter/texture_atlas_generator.py b/Blender/coa_tools/operators/exporter/texture_atlas_generator.py index ca13fd5..d72f1ff 100644 --- a/Blender/coa_tools/operators/exporter/texture_atlas_generator.py +++ b/Blender/coa_tools/operators/exporter/texture_atlas_generator.py @@ -272,7 +272,8 @@ def generate_uv_layout(name="texture_atlas", objects=None, width=256, height=256 render_collection = bpy.data.collections.new("COA Atlas Collection") context.scene.collection.children.link(render_collection) render_collection.hide_render = False - bpy.data.collections["COA Export Collection"].hide_render = True + if("COA Export Collection" in bpy.data.collections): + bpy.data.collections["COA Export Collection"].hide_render = True ### Extract texture data from given objects. Gives texture width, height and boundaries texture_data_list = TextureAtlasGenerator.get_sorted_texture_data(objects, output_scale) @@ -383,8 +384,9 @@ def generate_uv_layout(name="texture_atlas", objects=None, width=256, height=256 for vert in merged_uv_obj.data.vertices: vert.select = True vert.hide = False - bpy.data.collections["COA Export Collection"].hide_render = False + if("COA Export Collection" in bpy.data.collections): + bpy.data.collections["COA Export Collection"].hide_render = False return atlas_img, merged_uv_obj, atlas_data -# TextureAtlasGenerator.generate_uv_layout(name="texture_atlas", objects=bpy.context.selected_objects, width=256,height=256, max_width=1024, max_height=1024, margin=1, texture_bleed=0,square=True, output_scale=1.0) \ No newline at end of file +# TextureAtlasGenerator.generate_uv_layout(name="texture_atlas", objects=bpy.context.selected_objects, width=256,height=256, max_width=1024, max_height=1024, margin=1, texture_bleed=0,square=True, output_scale=1.0) diff --git a/Blender/coa_tools/properties.py b/Blender/coa_tools/properties.py index eacde07..5acac24 100644 --- a/Blender/coa_tools/properties.py +++ b/Blender/coa_tools/properties.py @@ -434,6 +434,8 @@ class SceneProperties(bpy.types.PropertyGroup): project_name: bpy.props.StringProperty(default="New Project", name="Project name") runtime_format: bpy.props.EnumProperty(default="CREATURE", description="Exports for choosen runtime.",items=(("CREATURE","Creature","Creature"),("DRAGONBONES","Dragonbones","Dragonbones"))) export_path: bpy.props.StringProperty(default="", name="Export Path",subtype="DIR_PATH") + armature_change: bpy.props.BoolProperty(default=False, name="Armature Name") + armature_name: bpy.props.StringProperty(default="Armature",name="Name") export_image_mode: bpy.props.EnumProperty(default="ATLAS", name="Image Mode",items=(("ATLAS","Atlas","Atlas"),("IMAGES","Images","Images"))) atlas_mode: bpy.props.EnumProperty(default="LIMIT_SIZE", name="Atlas Mode",items=(("AUTO_SIZE", "Auto Size", "Auto Size"),("LIMIT_SIZE","Limit Size","Limit Size"))) sprite_scale: bpy.props.FloatProperty(default=1.0, min=0.1, max=1.0, name="Sprite Output Scale", description="Define the Sprite Output Scale", step=0.1) From 5d69d03ec87d7bfd71253cdb991814f63eb1b6af Mon Sep 17 00:00:00 2001 From: kreezii Date: Sat, 28 Nov 2020 19:45:08 +0100 Subject: [PATCH 5/7] Blender 2.91 Fix --- Blender/coa_tools/operators/edit_armature.py | 316 +++++++++---------- 1 file changed, 158 insertions(+), 158 deletions(-) diff --git a/Blender/coa_tools/operators/edit_armature.py b/Blender/coa_tools/operators/edit_armature.py index ed43bbf..c4ed63e 100644 --- a/Blender/coa_tools/operators/edit_armature.py +++ b/Blender/coa_tools/operators/edit_armature.py @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' - + import bpy import bpy_extras import bpy_extras.view3d_utils @@ -32,7 +32,7 @@ import json from bpy.app.handlers import persistent from .. import functions -from .. functions_draw import * +from .. functions_draw import * import traceback class COATOOLS_OT_TooglePoseMode(bpy.types.Operator): @@ -64,11 +64,11 @@ class COATOOLS_OT_BindMeshToBones(bpy.types.Operator): bl_label = "Bind Mesh To Selected Bones" bl_description = "Bind mesh to selected bones." bl_options = {"REGISTER"} - + ob_name: StringProperty() armature = None sprite_object = None - + @classmethod def poll(cls, context): return True @@ -78,13 +78,13 @@ def execute(self, context): self.sprite_object = functions.get_sprite_object(obj) self.armature = functions.get_armature(self.sprite_object) functions.set_weights(self,context,obj) - + msg = '"'+obj.name+'"' + " has been bound to selected Bones." self.report({'INFO'},msg) return {"FINISHED"} - -######################################################################################################################################### Quick Armature + +######################################################################################################################################### Quick Armature class COATOOLS_TO_DrawBone(bpy.types.WorkSpaceTool): bl_space_type = 'VIEW_3D' bl_context_mode = 'EDIT_ARMATURE' @@ -104,7 +104,7 @@ class COATOOLS_TO_DrawBone(bpy.types.WorkSpaceTool): class COATOOLS_OT_QuickArmature(bpy.types.Operator): bl_idname = "coa_tools.quick_armature" bl_label = "Quick Armature" - + def __init__(self): self.distance = .1 self.cur_distance = 0 @@ -131,9 +131,9 @@ def __init__(self): self.armature_name = "" self.emulate_3_button = False self.obj_settings = {} - + self.cursor_location = Vector((0,0,0)) - + def project_cursor(self, event): coord = mathutils.Vector((event.mouse_region_x, event.mouse_region_y)) transform = bpy_extras.view3d_utils.region_2d_to_location_3d @@ -147,23 +147,23 @@ def project_cursor(self, event): #end = transform(region, rv3d, coord, bpy.context.space_data.region_3d.view_location) ### Viewport origin start = bpy_extras.view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) - + ### Cast ray from view to mouselocation - ray = bpy.context.scene.ray_cast(bpy.context.view_layer, start, (start+(end-start)*2000)-start ) - + ray = bpy.context.scene.ray_cast(bpy.context.view_layer.depsgraph, start, (start+(end-start)*2000)-start ) + ### ray_cast return values have changed after blender 2.67.0 ray = [ray[0],ray[4],ray[5],ray[1],ray[2]] - + return start, end, ray - + def create_armature(self,context): obj = bpy.context.active_object sprite_object = functions.get_sprite_object(obj) armature = functions.get_armature(sprite_object) - + for obj2 in context.selected_objects: obj2.select_set(False) - + if armature != None: context.view_layer.objects.active = armature armature.select_set(True) @@ -178,7 +178,7 @@ def create_armature(self,context): armature.show_in_front = True #amt.draw_type = "BBONE" return armature - + def create_default_bone_group(self,armature): default_bone_group = None if "default_bones" not in armature.pose.bone_groups: @@ -190,10 +190,10 @@ def create_default_bone_group(self,armature): def create_bones(self, context, armature): if armature != None: - + bpy.ops.object.mode_set(mode='EDIT') bone = armature.data.edit_bones.new("Bone") - + ### tag bones that will be locked bone["lock_z"] = True bone["lock_rot"] = True @@ -204,12 +204,12 @@ def create_bones(self, context, armature): bone.hide = True bone.bbone_x = .05 bone.bbone_z = .05 - + for bone2 in armature.data.edit_bones: bone2.select_head = False bone2.select_tail = False if bone2 != armature.data.edit_bones.active: - bone2.select = False + bone2.select = False if armature.data.edit_bones.active != None and armature.data.edit_bones.active.select == True: active_bone = armature.data.edit_bones.active bone.parent = active_bone @@ -219,22 +219,22 @@ def create_bones(self, context, armature): bone.use_connect = True active_bone.select_tail = True active_bone.select = False - - + + bone.select = True bone.select_head = True bone.select_tail = True armature.data.edit_bones.active = bone self.current_bone = bone - self.create_default_bone_group(armature) - + self.create_default_bone_group(armature) + def drag_bone(self,context, event ,bone=None): ### math.atan2(0.5, 0.5)*180/math.pi mouse_vec_norm = (self.cursor_location - self.mouse_click_vec).normalized() mouse_vec = (self.cursor_location - self.mouse_click_vec) angle = (math.atan2(mouse_vec_norm[0], mouse_vec_norm[2]) * 180 / math.pi) if bone != None: - + bone.hide = False cursor_local = self.armature.matrix_world.inverted() @ self.cursor_location cursor_local[1] = 0 @@ -251,7 +251,7 @@ def drag_bone(self,context, event ,bone=None): elif angle > 112.5 and angle < 157.5: ### down right bone.tail = (bone.head + Vector((mouse_vec[0],0,-mouse_vec[0]))) - elif angle > 157.5 or angle < -157.5: + elif angle > 157.5 or angle < -157.5: ### down bone.tail = Vector((bone.head[0],cursor_local[1],cursor_local[2])) elif angle > -157.5 and angle < -112.5: @@ -260,13 +260,13 @@ def drag_bone(self,context, event ,bone=None): elif angle > -112.5 and angle < -67.5: ### left bone.tail = Vector((cursor_local[0],cursor_local[1],bone.head[2])) - elif angle > -67.5 and angle < -22.5: + elif angle > -67.5 and angle < -22.5: ### left up bone.tail = (bone.head + Vector((mouse_vec[0],0,-mouse_vec[0]))) else: bone.tail = cursor_local return mouse_vec.magnitude, mouse_vec.magnitude / bpy.context.space_data.region_3d.view_distance - + def set_parent(self,context,obj): obj.select_set(True) bpy.ops.object.mode_set(mode='POSE') @@ -274,7 +274,7 @@ def set_parent(self,context,obj): bpy.ops.object.mode_set(mode='EDIT') obj.select_set(False) bpy.ops.ed.undo_push(message="Sprite "+obj.name+ " set parent") - + def return_ray_sprites(self,context,event): coord = mathutils.Vector((event.mouse_region_x, event.mouse_region_y)) transform = bpy_extras.view3d_utils.region_2d_to_location_3d @@ -285,8 +285,8 @@ def return_ray_sprites(self,context,event): start = bpy_extras.view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) return functions.ray_cast(start,end,[]) - - + + def modal(self, context, event): ## skip everything if different tool is selected if functions.get_active_tool("EDIT_ARMATURE") != "coa_tools.draw_bone": @@ -294,18 +294,18 @@ def modal(self, context, event): try: self.in_view_3d = functions.check_region(context,event) - + if event.alt: - bpy.context.window.cursor_set("EYEDROPPER") - elif not event.alt and self.in_view_3d: + bpy.context.window.cursor_set("EYEDROPPER") + elif not event.alt and self.in_view_3d: bpy.context.window.cursor_set("PAINT_BRUSH") else: - bpy.context.window.cursor_set("DEFAULT") - + bpy.context.window.cursor_set("DEFAULT") + scene = context.scene ob = context.active_object - - + + ### lock posebone scale z value self.sprite_object = bpy.data.objects[self.sprite_object_name] self.armature = bpy.data.objects[self.armature_name] @@ -320,8 +320,8 @@ def modal(self, context, event): pose_bone = ob.pose.bones[bone.name] pose_bone.lock_rotation[0] = True pose_bone.lock_rotation[1] = True - del bone["lock_rot"] - + del bone["lock_rot"] + if self.in_view_3d: self.mouse_press_hist = self.mouse_press mouse_button = None @@ -329,21 +329,21 @@ def modal(self, context, event): keyconfig = wm.keyconfigs.active mouse_button = 'LEFTMOUSE' ### Set Mouse click - - + + if event.ctrl == False and (event.value == 'PRESS') and event.type == mouse_button and self.mouse_press == False: self.mouse_press = True elif event.value in ['RELEASE','NOTHING'] and (event.type == mouse_button): self.mouse_press = False ### Cast Ray from mousePosition and set Cursor to hitPoint rayStart,rayEnd, ray = self.project_cursor(event) - + if ray[0] == True and ray[1] != None: self.cursor_location = ray[3] elif rayEnd != None: self.cursor_location = rayEnd self.cursor_location[1] = context.active_object.location[1] - + if event.value in ["RELEASE"]: if self.object_hover_hist != None: self.object_hover_hist.show_in_front = False @@ -354,8 +354,8 @@ def modal(self, context, event): self.object_hover.show_in_front = False self.object_hover.select_set(False) self.object_hover.show_name = False - - + + if not event.alt and not event.ctrl: self.object_hover = None ### mouse just pressed @@ -369,21 +369,21 @@ def modal(self, context, event): if context.active_bone != None: bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Y') return {'RUNNING_MODAL'} - ### mouse release + ### mouse release elif not self.mouse_press and self.mouse_press_hist and self.current_bone != None: bpy.ops.ed.undo_push(message="Add Bone: "+self.current_bone.name) - self.current_bone.hide = False + self.current_bone.hide = False self.current_bone = None self.mouse_click_vec = Vector((1000000,1000000,1000000)) - + self.set_waits = True bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='EDIT') - self.set_waits = False - + self.set_waits = False + elif (event.alt or "ALT" in event.type) and not event.ctrl and not event.type == "P" and event.type != "A": self.object_hover_hist = self.object_hover - + hover_objects = self.return_ray_sprites(context,event) distance = 1000000000 if len(hover_objects) > 0: @@ -423,19 +423,19 @@ def modal(self, context, event): functions.set_weights(self, context, self.object_hover) msg = '"' + self.object_hover.name + '"' + " has been bound to selected Bones." self.report({'INFO'}, msg) - self.object_hover.coa_tools.slot_index = prev_index + self.object_hover.coa_tools.slot_index = prev_index return{'RUNNING_MODAL'} - - ### finish mode + + ### finish mode if context.active_object == None or (context.active_object != None and context.active_object != self.armature) or (context.active_object.mode != "EDIT" and context.active_object.type == "ARMATURE" and self.set_waits == False) or not self.sprite_object.coa_tools.edit_armature: return self.exit_edit_mode(context) - + except Exception as e: traceback.print_exc() self.report({"ERROR"},"An Error occured, please check the console for more information") return self.exit_edit_mode(context) return {'PASS_THROUGH'} - + def exit_edit_mode(self,context): functions.set_active_tool(self, context, "builtin.select") try: @@ -454,12 +454,12 @@ def exit_edit_mode(self,context): for pose_bone in context.active_object.pose.bones: if "default_bones" in context.active_object.pose.bone_groups and pose_bone.bone_group == None: pose_bone.bone_group = context.active_object.pose.bone_groups["default_bones"] - + #lock_sprites(context,get_sprite_object(context.active_object),get_sprite_object(context.active_object).lock_sprites) self.sprite_object = bpy.data.objects[self.sprite_object_name] self.sprite_object.coa_tools.edit_armature = False self.sprite_object.coa_tools.edit_mode = "OBJECT" - + ### restore previous selection for obj in bpy.context.scene.objects: obj.select_set(False) @@ -469,19 +469,19 @@ def exit_edit_mode(self,context): obj.select_set(True) context.view_layer.objects.active = bpy.data.objects[self.active_object_name] if self.active_object_name in bpy.data.objects else None context.preferences.inputs.use_mouse_emulate_3_button = self.emulate_3_button - + ### restore object settings for obj_name in self.obj_settings: obj = bpy.data.objects[obj_name] if obj_name in bpy.data.objects else None if obj != None: obj.show_name = self.obj_settings[obj_name]["show_name"] return{'FINISHED'} - + def execute(self, context): #bpy.ops.wm.coa_modal() ### start coa modal mode if not running self.emulate_3_button = context.preferences.inputs.use_mouse_emulate_3_button context.preferences.inputs.use_mouse_emulate_3_button = False - + ### store object settings for obj in context.scene.objects: # self.obj_settings[obj] = {"show_in_front":obj.show_in_front, "show_name":obj.show_name} @@ -491,17 +491,17 @@ def execute(self, context): if obj.select_get(): self.selected_object_names.append(obj.name) self.active_object_name = context.active_object.name - + self.sprite_object = functions.get_sprite_object(context.active_object) self.sprite_object_name = str(self.sprite_object.name) self.sprite_object.coa_tools.edit_armature = True self.sprite_object.coa_tools.edit_mode = "ARMATURE" - + functions.lock_sprites(context,functions.get_sprite_object(context.active_object),False) self.armature = self.create_armature(context) self.armature_name = str(self.armature.name) - - self.armature.coa_tools.hide = False + + self.armature.coa_tools.hide = False self.armature_mode = context.active_object.mode bpy.ops.object.mode_set(mode='EDIT') @@ -512,7 +512,7 @@ def execute(self, context): functions.set_active_tool(self, context, "coa_tools.draw_bone") context.window_manager.modal_handler_add(self) - + ### call draw code # args = () # self.draw_handler = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_px, args, "WINDOW", "POST_PIXEL") @@ -520,22 +520,22 @@ def execute(self, context): def cancel(self, context): return {'CANCELLED'} - + def draw_callback_px(self): pass # draw_edit_mode(self,bpy.context,color=[0.461840, 0.852381, 1.000000, 1.000000],text="Edit Armature Mode",offset=0) - - + + ######################################################################################################################################### Set Stretch To Constraint class COATOOLS_OT_SetStretchBone(bpy.types.Operator): bl_idname = "coa_tools.set_stretch_bone" bl_label = "Set Stretch Bone" - + def execute(self,context): armature = context.active_object p_bone = armature.pose.bones[context.active_pose_bone.name] bpy.ops.object.mode_set(mode="EDIT") - + bone_name = "Stretch_"+p_bone.name stretch_to_bone = armature.data.edit_bones.new(bone_name) stretch_to_bone.use_deform = False @@ -545,16 +545,16 @@ def execute(self,context): stretch_to_bone.head = p_bone.tail stretch_to_bone.tail = Vector((p_bone.tail[0],0, p_bone.tail[2] + length * .5)) bpy.ops.object.mode_set(mode="POSE") - + stretch_to_constraint = p_bone.constraints.new("STRETCH_TO") stretch_to_constraint.target = context.active_object stretch_to_constraint.subtarget = bone_name - stretch_to_constraint.keep_axis = "PLANE_Z" + stretch_to_constraint.keep_axis = "PLANE_Z" stretch_to_constraint.volume = "VOLUME_X" functions.set_bone_group(self, context.active_object, context.active_object.pose.bones[bone_name],group="stretch_to",theme = "THEME07") return{'FINISHED'} -######################################################################################################################################### Set IK Constraint +######################################################################################################################################### Set IK Constraint class COATOOLS_OT_RemoveIK(bpy.types.Operator): bl_idname = "coa_tools.remove_ik" @@ -571,7 +571,7 @@ def execute(self, context): obj = context.active_object pose_bone = bpy.context.active_pose_bone if obj.type == "ARMATURE": - + ik_const_found = False for bone in obj.pose.bones: for const in bone.constraints: @@ -579,13 +579,13 @@ def execute(self, context): ik_const_found = True if ik_const_found == False: self.report({"WARNING"}, "No IK Constraint found to delete.") - return{"CANCELLED"} - - + return{"CANCELLED"} + + for bone in obj.pose.bones: copy_loc = None copy_rot = None - + for const in bone.constraints: if const.type == "COPY_LOCATION" and const.subtarget == pose_bone.name: copy_loc = const @@ -601,24 +601,24 @@ def execute(self, context): obj.data.bones[bone.name].layers[1] = False obj.data.bones.active = obj.data.bones[bone.name] obj.data.bones[bone.name].select = True - + bpy.ops.object.mode_set(mode="EDIT") obj.data.edit_bones.remove(obj.data.edit_bones[pose_bone.name]) bpy.ops.object.mode_set(mode="POSE") - - + + return {"FINISHED"} - + class COATOOLS_OT_SetIK(bpy.types.Operator): bl_idname = "coa_tools.set_ik" bl_label = "Set IK Bone" - + replace_bone: BoolProperty(name="Replace IK Bone",description="Replaces active Bone as IK Bone", default=True) - + def invoke(self, context, event): - wm = context.window_manager - return wm.invoke_props_dialog(self) + wm = context.window_manager + return wm.invoke_props_dialog(self) def execute(self,context): bone = context.active_object.pose.bones[context.active_pose_bone.name] @@ -627,18 +627,18 @@ def execute(self,context): if self.replace_bone: ik_bone = bone.parent else: - ik_bone = bone + ik_bone = bone next_bone = bone ik_length = 0 while next_bone != bone2 and next_bone.parent != None: - ik_length += 1 + ik_length += 1 next_bone = next_bone.parent if not self.replace_bone: ik_length += 1 - + for bone3 in context.active_object.data.bones: bone3.select = False - + bpy.ops.object.mode_set(mode="EDIT") ik_target_name = "IK_" + bone.name ik_target = context.active_object.data.edit_bones.new("IK_" + bone.name) @@ -649,12 +649,12 @@ def execute(self,context): ik_target.tail = bone.tail else: ik_target.head = bone.tail - ik_target.tail = ik_target.head + Vector(((bone.tail - bone.head).length,0,0)) + ik_target.tail = ik_target.head + Vector(((bone.tail - bone.head).length,0,0)) ik_target.roll = context.active_object.data.edit_bones[bone.name].roll bpy.ops.object.mode_set(mode="POSE") context.active_object.data.bones[ik_target_name].select = True context.active_object.data.bones.active = context.active_object.data.bones[ik_target_name] - + ik_bone.lock_ik_x = True ik_bone.lock_ik_y = True #ik_bone.ik_stiffness_z = .9 @@ -662,23 +662,23 @@ def execute(self,context): ik_const.target = context.active_object ik_const.subtarget = ik_target_name ik_const.chain_count = ik_length - + functions.set_bone_group(self, context.active_object, context.active_object.pose.bones[ik_target_name]) - + if self.replace_bone: copy_loc_const = bone.constraints.new("COPY_LOCATION") copy_loc_const.target = context.active_object copy_loc_const.subtarget = ik_target_name - + copy_rot_const = bone.constraints.new("COPY_ROTATION") copy_rot_const.target = context.active_object copy_rot_const.subtarget = ik_target_name context.active_object.data.bones[bone.name].layers[1] = True context.active_object.data.bones[bone.name].layers[0] = False - + bpy.ops.ed.undo_push(message="Set Ik") return{'FINISHED'} - + class COATOOLS_OT_CreateStretchIK(bpy.types.Operator): bl_idname = "coa_tools.create_stretch_ik" bl_label = "Create Stretch Ik" @@ -697,7 +697,7 @@ def get_bones(self,context,bones): p_bone = p_bone.parent while len(c_bone.children) > 0 and c_bone.children[0] in bones: c_bone = c_bone.children[0] - + ik_bones = [] ik_bone = p_bone.children[0] while ik_bone not in ik_bones and ik_bone != c_bone: @@ -706,9 +706,9 @@ def get_bones(self,context,bones): if child.select: ik_bone = child break - + return [p_bone,c_bone,ik_bones] - + def duplicate_bones(self,context,bones): bpy.ops.armature.select_all(action='DESELECT') new_bones = [] @@ -718,7 +718,7 @@ def duplicate_bones(self,context,bones): new_bone.tail = bone.tail new_bone.head = bone.head new_bones.append(new_bone) - + if i == 0: new_bone.parent = bone.parent else: @@ -727,24 +727,24 @@ def duplicate_bones(self,context,bones): new_bone.select = True new_bone.select_head = True new_bone.select_tail = True - return new_bones - - + return new_bones + + def execute(self, context): obj = context.active_object - + if len(context.selected_pose_bones) < 3: self.report({'WARNING'},"Select 3 bones at least.") return{"CANCELLED"} - + ####################### create all needed bones ####################### - + bpy.ops.object.mode_set(mode="EDIT") bones = context.selected_bones[:] - + ### get deform bones p_bone_def, c_bone_def, ik_bones_def = self.get_bones(context,bones) - + ### duplicate deform bones self.duplicate_bones(context,[p_bone_def]+ik_bones_def+[c_bone_def]) ### get control bones @@ -756,8 +756,8 @@ def execute(self, context): ik_bone.name = ik_bones_def[i].name + "_CTRL" c_bone_ctrl.use_connect = False c_bone_ctrl.parent = None - - + + ### create stretch to bone joint_bones_ctrl = [] for i,ik_bone in enumerate(ik_bones_ctrl): @@ -772,32 +772,32 @@ def execute(self, context): joint_bone_ctrl.use_inherit_scale = False joint_bone_ctrl.use_inherit_rotation = False joint_bones_ctrl.append(joint_bone_ctrl) - + ####################### create all needed constraints ####################### - + ### get names from edit bone names while in edit mode. Otherwise Editbones will not be available to gather name from p_bone_ctrl_name = str(p_bone_ctrl.name) c_bone_ctrl_name = str(c_bone_ctrl.name) - + ik_bone_ctrl_names = [] for ik_bone in ik_bones_ctrl: ik_bone_ctrl_names.append(str(ik_bone.name)) - + p_bone_def_name = str(p_bone_def.name) c_bone_def_name = str(c_bone_def.name) - + ik_bone_def_names = [] for ik_bone in ik_bones_def: ik_bone_def_names.append(str(ik_bone.name)) - + ik_bone_ctrl_names = [] for ik_bone in ik_bones_ctrl: ik_bone_ctrl_names.append(str(ik_bone.name)) - + joint_bone_ctrl_names = [] for join_bone in joint_bones_ctrl: joint_bone_ctrl_names.append(str(join_bone.name)) - + ### change mode into pose mode bpy.ops.object.mode_set(mode="OBJECT") bpy.ops.object.mode_set(mode="EDIT") @@ -809,118 +809,118 @@ def execute(self, context): ik_bones_def = [] for ik_bone_name in ik_bone_def_names: ik_bones_def.append(obj.pose.bones[ik_bone_name]) - + ### get pose ctrl bones p_bone_ctrl = obj.pose.bones[p_bone_ctrl_name] c_bone_ctrl = obj.pose.bones[c_bone_ctrl_name] ik_bones_ctrl = [] for ik_bone_name in ik_bone_ctrl_names: ik_bones_ctrl.append(obj.pose.bones[ik_bone_name]) - + joint_bones_ctrl = [] for joint_bone_name in joint_bone_ctrl_names: joint_bones_ctrl.append(obj.pose.bones[joint_bone_name]) - + ### disable deforming for all ctrl bones ctrl_bones = [p_bone_ctrl, c_bone_ctrl] + ik_bones_ctrl + joint_bones_ctrl for bone in ctrl_bones: bone = obj.data.bones[bone.name] bone.use_deform = False - + c = p_bone_def.constraints.new("LIMIT_ROTATION") c.owner_space = "POSE" c.use_limit_z = True - + c = p_bone_def.constraints.new("STRETCH_TO") c.target = obj c.subtarget = joint_bones_ctrl[0].name c.keep_axis = "PLANE_Z" const_p_bone = c - - + + c = p_bone_def.constraints.new("LIMIT_SCALE") c.owner_space = "POSE" c.use_min_z = True c.use_max_z = True c.max_z = 1.0 c.min_z = 1.0 - + const_ik_bones = [] for i,ik_bone_def in enumerate(ik_bones_def): c = ik_bone_def.constraints.new("LIMIT_ROTATION") c.owner_space = "POSE" c.use_limit_z = True - + c = ik_bone_def.constraints.new("STRETCH_TO") c.target = obj c.keep_axis = "PLANE_Z" const_ik_bones.append(c) if i == len(ik_bones_def)-1: c.subtarget = c_bone_ctrl.name - else: + else: c.subtarget = joint_bones_ctrl[i+1].name - + c = ik_bone_def.constraints.new("LIMIT_SCALE") c.owner_space = "POSE" c.use_min_z = True c.use_max_z = True c.max_z = 1.0 c.min_z = 1.0 - - + + c = c_bone_def.constraints.new("COPY_TRANSFORMS") c.target = obj c.subtarget = c_bone_ctrl.name const_c_bone = c - + c = ik_bones_ctrl[len(ik_bones_ctrl)-1].constraints.new("IK") c.target = obj c.subtarget = c_bone_ctrl.name c.chain_count = len(ik_bones_ctrl) + 1 const_ik = c - + for ik_bone_ctrl in ik_bones_ctrl: ik_bone_ctrl.lock_ik_x = True ik_bone_ctrl.lock_ik_y = True - + ik_bone_ctrl.ik_stretch = .2 p_bone_ctrl.ik_stretch = .2 - + ### move bones to other layers hide_bone_names = [p_bone_ctrl_name, p_bone_def_name, c_bone_def_name] + ik_bone_ctrl_names + ik_bone_def_names for bone_name in hide_bone_names: obj.data.bones[bone_name].layers[1] = True obj.data.bones[bone_name].layers[0] = False - + ### store bones and constraints in Stretch IK Pointer Property p_bone_def["coa_stretch_ik_data"] = str([c_bone_ctrl.name,"p_bone_def"]) c_bone_def["coa_stretch_ik_data"] = str([c_bone_ctrl.name,"c_bone_def"]) for ik_bone_def in ik_bones_def: ik_bone_def["coa_stretch_ik_data"] = str([c_bone_ctrl.name,"ik_bone_def"]) - + p_bone_ctrl["coa_stretch_ik_data"] = str([c_bone_ctrl.name,"p_bone_ctrl"]) c_bone_ctrl["coa_stretch_ik_data"] = str([c_bone_ctrl.name,"c_bone_ctrl"]) - + for ik_bone_ctrl in ik_bones_ctrl: ik_bone_ctrl["coa_stretch_ik_data"] = str([c_bone_ctrl.name,"ik_bone_ctrl"]) for joint_bone_ctrl in joint_bones_ctrl: joint_bone_ctrl["coa_stretch_ik_data"] = str([c_bone_ctrl.name,"joint_bone_ctrl"]) - + ### set bone colors functions.set_bone_group(self, obj, c_bone_ctrl,group = "ik_group" ,theme = "THEME09") for joint_bone_ctrl in joint_bones_ctrl: functions.set_bone_group(self, obj, joint_bone_ctrl,group = "ik_group" ,theme = "THEME09") - + return {"FINISHED"} - + class COATOOLS_OT_RemoveStretchIK(bpy.types.Operator): bl_idname = "coa_tools.remove_stretch_ik" bl_label = "Remove Stretch Ik" bl_description = "" bl_options = {"REGISTER"} - + stretch_ik_name: StringProperty() - + @classmethod def poll(cls, context): return True @@ -928,31 +928,31 @@ def poll(cls, context): def execute(self, context): obj = context.active_object bpy.ops.object.mode_set(mode="EDIT") - + for bone in obj.pose.bones: e_bone = obj.data.edit_bones[bone.name] if "coa_stretch_ik_data" in bone: name = eval(bone["coa_stretch_ik_data"])[0] type = eval(bone["coa_stretch_ik_data"])[1] - + if name == self.stretch_ik_name: if "_ctrl" in type: obj.data.edit_bones.remove(e_bone) elif "_def" in type: for const in bone.constraints: - bone.constraints.remove(const) - - bpy.ops.object.mode_set(mode="POSE") - + bone.constraints.remove(const) + + bpy.ops.object.mode_set(mode="POSE") + del(bone["coa_stretch_ik_data"]) - + bone = obj.data.bones[bone.name] bone.select = True obj.data.bones.active = bone bone.layers[0] = True bone.layers[1] = False - + bpy.ops.object.mode_set(mode="EDIT") - bpy.ops.object.mode_set(mode="POSE") - + bpy.ops.object.mode_set(mode="POSE") + return {"FINISHED"} From d9afd10e7b1d0cbb0eb5768ba86e12270dfd7476 Mon Sep 17 00:00:00 2001 From: kreezii Date: Sat, 28 Nov 2020 19:54:07 +0100 Subject: [PATCH 6/7] Blender 2.91 Fix --- Blender/coa_tools/operators/edit_mesh.py | 430 +++++++++++------------ 1 file changed, 215 insertions(+), 215 deletions(-) diff --git a/Blender/coa_tools/operators/edit_mesh.py b/Blender/coa_tools/operators/edit_mesh.py index 85cbf94..2d0d41e 100644 --- a/Blender/coa_tools/operators/edit_mesh.py +++ b/Blender/coa_tools/operators/edit_mesh.py @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' - + import bpy import bpy_extras import bpy_extras.view3d_utils @@ -27,7 +27,7 @@ import bmesh from bpy.props import FloatProperty, IntProperty, BoolProperty, StringProperty, CollectionProperty, FloatVectorProperty, EnumProperty, IntVectorProperty from .. import functions -from .. functions_draw import * +from .. functions_draw import * import bgl import blf from math import radians, degrees @@ -58,7 +58,7 @@ def collapse_short_edges(bm,obj,threshold=1.0): if not vert.is_boundary: verts.append(vert) bmesh.update_edit_mesh(obj.data) - + bmesh.ops.remove_doubles(bm,verts=verts,dist=edges_len_average * threshold) bmesh.update_edit_mesh(obj.data) @@ -80,17 +80,17 @@ def get_average_edge_length(bm,obj): def clean_boundary_edges(bm,obj): edges_len_average, shortest_edge = get_average_edge_length(bm,obj) edges = [] - + for edge in bm.edges: if edge.calc_length() < edges_len_average * .12 and not edge.tag: edges.append(edge) - bmesh.ops.collapse(bm,edges=edges,uvs=False) - bmesh.update_edit_mesh(obj.data) + bmesh.ops.collapse(bm,edges=edges,uvs=False) + bmesh.update_edit_mesh(obj.data) def average_edge_cuts(bm,obj,cuts=1): ### collapse short edges edges_len_average, shortest_edge = get_average_edge_length(bm,obj) - + subdivide_edges = [] for edge in bm.edges: cut_count = int(edge.calc_length()/shortest_edge) * cuts @@ -101,7 +101,7 @@ def average_edge_cuts(bm,obj,cuts=1): for edge in subdivide_edges: bmesh.ops.subdivide_edges(bm,edges=[edge[0]],cuts=edge[1]) bmesh.update_edit_mesh(obj.data) - + def triangle_fill(bm,obj): edges = [] for edge in bm.edges: @@ -115,9 +115,9 @@ def triangle_fill(bm,obj): return True def triangulate(bm,obj): - bmesh.ops.triangulate(bm,faces=bm.faces) + bmesh.ops.triangulate(bm,faces=bm.faces) bmesh.update_edit_mesh(obj.data) - + def smooth_verts(bm,obj): ### smooth verts smooth_verts = [] @@ -125,20 +125,20 @@ def smooth_verts(bm,obj): if not vert.is_boundary: smooth_verts.append(vert) for i in range(50): - #bmesh.ops.smooth_vert(bm,verts=smooth_verts,factor=1.0,use_axis_x=True,use_axis_y=True,use_axis_z=True) - bmesh.ops.smooth_vert(bm,verts=smooth_verts,factor=1.0,use_axis_x=True,use_axis_y=True,use_axis_z=True) + #bmesh.ops.smooth_vert(bm,verts=smooth_verts,factor=1.0,use_axis_x=True,use_axis_y=True,use_axis_z=True) + bmesh.ops.smooth_vert(bm,verts=smooth_verts,factor=1.0,use_axis_x=True,use_axis_y=True,use_axis_z=True) bmesh.update_edit_mesh(obj.data) - + def clean_verts(bm,obj): ### find corrupted faces - faces = [] + faces = [] for face in bm.faces: i = 0 for edge in face.edges: if not edge.is_manifold: i += 1 if i == len(face.edges): - faces.append(face) + faces.append(face) bmesh.ops.delete(bm,geom=faces,context="FACES_ONLY") edges = [] @@ -152,12 +152,12 @@ def clean_verts(bm,obj): if edge not in edges: edges.append(edge) bmesh.ops.collapse(bm,edges=edges) - + bmesh.update_edit_mesh(obj.data) for vert in bm.verts: if not vert.is_boundary: vert.select = False - + verts = [] for vert in bm.verts: if len(vert.link_edges) in [3,4] and not vert.is_boundary: @@ -172,15 +172,15 @@ def remove_doubles(obj,edge_average_len,edge_min_len): if not vert.hide: verts.append(vert) bmesh.ops.remove_doubles(bm,verts=verts,dist=0.0001) - bmesh.update_edit_mesh(obj.data) - + bmesh.update_edit_mesh(obj.data) + class COATOOLS_OT_ReprojectSpriteTexture(bpy.types.Operator): bl_idname = "coa_tools.reproject_sprite_texture" bl_label = "Reproject Sprite Texture" bl_description = "" bl_options = {"REGISTER"} - + def reproject(self,context): ### unwrap obj = context.active_object @@ -188,13 +188,13 @@ def reproject(self,context): obj.data.coa_tools.hide_base_sprite = False bpy.ops.object.mode_set(mode="EDIT",toggle=False) bm = bmesh.from_edit_mesh(obj.data) - + selected_verts = [] for vert in bm.verts: if vert.select: selected_verts.append(vert.co) #vert.select = True - + for face in bm.faces: face.select = True for vert in bm.verts: @@ -203,21 +203,21 @@ def reproject(self,context): object_matrix = obj.matrix_world.copy() obj.rotation_euler = [0,0,0] obj.scale = [1,1,1] - bpy.ops.uv.project_from_view(camera_bounds=False, correct_aspect=True, scale_to_bounds=True) + bpy.ops.uv.project_from_view(camera_bounds=False, correct_aspect=True, scale_to_bounds=True) obj.matrix_world = object_matrix for face in bm.faces: face.select = False - bmesh.update_edit_mesh(obj.data) - + bmesh.update_edit_mesh(obj.data) + for vert in bm.verts: if vert.co in selected_verts: vert.select = True else: vert.select = False - - bmesh.update_edit_mesh(obj.data) + + bmesh.update_edit_mesh(obj.data) obj.data.coa_tools.hide_base_sprite = hide_base_sprite - + @classmethod def poll(cls, context): return True @@ -225,19 +225,19 @@ def poll(cls, context): def execute(self, context): self.reproject(context) return {"FINISHED"} - + class COATOOLS_OT_GenerateMeshFromEdgesAndVerts(bpy.types.Operator): bl_idname = "coa_tools.generate_mesh_from_edges_and_verts" bl_label = "Generate Mesh From Edges And Verts" bl_description = "" - bl_options = {"REGISTER"} + bl_options = {"REGISTER"} def cleanup_and_fill_mesh(self,obj,bm): context = bpy.context wm = context.window_manager wm.progress_begin(0,100) - + def edge_is_intersecting(e2,bm): for e1 in bm.edges: edge_visible = not e1.hide @@ -246,8 +246,8 @@ def edge_is_intersecting(e2,bm): i = geometry.intersect_line_line_2d(e1.verts[0].co.xz, e1.verts[1].co.xz, e2[0].co.xz, e2[1].co.xz) if i != None: return True - return False - + return False + def get_linked_verts(vert): linked_verts = [vert] outer_verts = [vert] @@ -271,9 +271,9 @@ def get_linked_verts(vert): if vert.hide: face_editable = False break - if face_editable: + if face_editable: faces.append(face) - + bmesh.ops.delete(bm,geom=faces,context="FACES_ONLY") wm.progress_update(30) ### delete double verts @@ -286,20 +286,20 @@ def get_linked_verts(vert): verts.append(edge.verts[0]) if edge.verts[1] not in verts: verts.append(edge.verts[1]) - bmesh.ops.remove_doubles(bm,verts=verts,dist=0.01) - + bmesh.ops.remove_doubles(bm,verts=verts,dist=0.01) + ### delete intersecting lines and add vertices at intersectionpoints intersection_points = [] to_be_deleted = [] for e1 in bm.edges: for e2 in bm.edges: edges_not_visible = not e1.hide and not e2.hide - + edges_share_points = e1.verts[0].co.xz in [e2.verts[0].co.xz, e2.verts[1].co.xz] or e1.verts[1].co.xz in [e2.verts[0].co.xz, e2.verts[1].co.xz] - + if e1 != e2 and not edges_share_points and edges_not_visible: i = geometry.intersect_line_line_2d(e1.verts[0].co.xz, e1.verts[1].co.xz, e2.verts[0].co.xz, e2.verts[1].co.xz) - + if i != None: i_3d = Vector((i[0],e1.verts[0].co[1],i[1])) if e1 not in to_be_deleted: @@ -312,7 +312,7 @@ def get_linked_verts(vert): bm.edges.remove(edge) for p in intersection_points: bm.verts.new(p) - + def get_vertex_loops(bm): ### find single vertex loops all_verts = [] @@ -323,7 +323,7 @@ def get_vertex_loops(bm): loop_list = get_linked_verts(vert) vert_loops.append(loop_list) all_verts += loop_list - return vert_loops + return vert_loops ### connect loose verts connected_edges = [] for vert in bm.verts: @@ -342,8 +342,8 @@ def get_vertex_loops(bm): edge_center = (vert_a.co+vert_b.co) * .5 if edge_center not in connected_edges: bm.edges.new([vert_a,vert_b]) - connected_edges.append(edge_center) - + connected_edges.append(edge_center) + ### connect loose edges vert_loops = get_vertex_loops(bm) connected_edges = [] @@ -362,21 +362,21 @@ def get_vertex_loops(bm): edge2 = (vert.co - vert2.co).normalized() if edge1.length > 0 and edge2.length > 0: angle = degrees(edge1.angle(edge2)) - + if (vert.co - vert2.co).magnitude < distance and vert2 not in exclude_verts and abs(angle) > 30 and not edge_is_intersecting([vert,vert2],bm): - + distance = (vert.co - vert2.co).magnitude vert_a = vert vert_b = vert2 - - ### connect nearest points and check + + ### connect nearest points and check ### if they haven't been connected yet by finding the edge center if vert_a != None and vert_b != None: edge_center = (vert_a.co+vert_b.co) * .5 if edge_center not in connected_edges: bm.edges.new([vert_a,vert_b]) - connected_edges.append(edge_center) - + connected_edges.append(edge_center) + wm.progress_update(100) ### find nearest vertex of different loops and connect vert_loops = get_vertex_loops(bm) @@ -384,11 +384,11 @@ def get_vertex_loops(bm): if len(vert_loops) > 1: ### loop over all edge loops and find nearest vertex points of two loops to connect for i,loop in enumerate(vert_loops): - + distance = 1000000000000000 vert_a = None vert_b = None - + for j,loop_next in enumerate(vert_loops): if j != i: for vert in loop: @@ -397,14 +397,14 @@ def get_vertex_loops(bm): distance = (vert.co - vert2.co).magnitude vert_a = vert vert_b = vert2 - - ### connect nearest points and check + + ### connect nearest points and check ### if they haven't been connected yet by finding the edge center if vert_a != None and vert_b != None: edge_center = (vert_a.co+vert_b.co) * .5 if edge_center not in connected_edges: bm.edges.new([vert_a,vert_b]) - connected_edges.append(edge_center) + connected_edges.append(edge_center) ### store existing edges center @@ -428,7 +428,7 @@ def get_vertex_loops(bm): delete_edges.append(edge) bmesh.ops.delete(bm, geom=delete_edges, context="EDGES") - delete_edges = [] + delete_edges = [] for edge in bm.edges: if not edge.hide and edge.is_wire and not edge.verts[0].hide and not edge.verts[1].hide: delete_edges.append(edge) @@ -444,25 +444,25 @@ def get_vertex_loops(bm): if vert.hide: face_editable = False break - if face_editable: + if face_editable: faces.append(face) - bmesh.ops.triangulate(bm,faces=faces) - - ### update mesh + bmesh.ops.triangulate(bm,faces=faces) + + ### update mesh bmesh.update_edit_mesh(obj.data) wm.progress_end() - + @classmethod def poll(cls, context): return True def execute(self, context): - + obj = bpy.context.active_object bm = bmesh.from_edit_mesh(obj.data) self.cleanup_and_fill_mesh(obj,bm) bpy.ops.coa_tools.reproject_sprite_texture() - + return {"FINISHED"} ######################################################################################################################################### Draw Contours @@ -497,10 +497,10 @@ class COATOOLS_TO_DrawPolygon(bpy.types.WorkSpaceTool): class COATOOLS_OT_DrawContour(bpy.types.Operator): bl_idname = "coa_tools.edit_mesh" bl_label = "Edit Mesh" - + mode: StringProperty(default="EDIT_MESH") new_shape_name: StringProperty() - + def __init__(self): self.type = "" self.value = "" @@ -522,7 +522,7 @@ def __init__(self): self.in_view_3d = False self.nearest_vertex_co = Vector((0,0,0)) self.contour_length = 0 - + self.selected_verts_count = 0 self.selected_vert_coord = None self.visible_verts = [] @@ -531,12 +531,12 @@ def __init__(self): self.edge_slide_points = [] self.new_added_edges = [] self.cut_edge = False - + self.edit_object = None self.edit_object_name = "" self.texture_preview_object = None self.texture_preview_object_name = "" - + self.bone = None self.bone_shape = None self.draw_bounds = False @@ -546,16 +546,16 @@ def __init__(self): self.type_prev = "" self.value_prev = "" self.prev_coa_view = "" - + self.armature = None self.armature_pose_mode = "" - + self.snapped_vert_coord, self.point_type, self.bm_obj, self.verts_edges_data = [Vector((0,0,0)),None,None,None] - + self.click_drag = False self.first_added_vert = None self.delete_stroke_points = [] - + def project_cursor(self, event): coord = mathutils.Vector((event.mouse_region_x, event.mouse_region_y)) transform = bpy_extras.view3d_utils.region_2d_to_location_3d @@ -569,29 +569,29 @@ def project_cursor(self, event): #end = transform(region, rv3d, coord, bpy.context.space_data.region_3d.view_location) ### Viewport origin start = bpy_extras.view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) - + ### Cast ray from view to mouselocation - ray = bpy.context.scene.ray_cast(bpy.context.view_layer, start, (start+(end-start) * 2000)-start ) + ray = bpy.context.scene.ray_cast(bpy.context.view_layer.depsgraph, start, (start+(end-start) * 2000)-start ) ray = [ray[0], ray[4], ray[5], ray[1], ray[2]] return start, end, ray def set_paint_distance(self,context,ray): ob = context.active_object scene = context.scene - + bpy.ops.object.mode_set(mode='OBJECT') if len(ob.data.vertices)==0: bpy.ops.object.mode_set(mode='EDIT') return 0.0 - + vert_loc = ob.data.vertices[len(ob.data.vertices)-1].co distance = (ray - vert_loc - ob.location).magnitude bpy.ops.object.mode_set(mode='EDIT') return distance - + def limit_value(self,value,minn,maxn): return max(min(maxn,value),minn) - + def limit_cursor_by_bounds(self,context,location): if self.mode == "EDIT_MESH": obj = context.active_object @@ -599,16 +599,16 @@ def limit_cursor_by_bounds(self,context,location): for point in self.bounds: bounds.append(obj.matrix_world.inverted() @ point) location = obj.matrix_world.inverted() @ location - + location[0] = self.limit_value(location[0], bounds[1][0], bounds[2][0]) location[2] = self.limit_value(location[2], bounds[0][2], bounds[1][2]) location = obj.matrix_world @ location return location - - + + def clean_mesh(self,obj): bm = bmesh.from_edit_mesh(obj.data) - + faces = [] for face in bm.faces: if not face.hide: @@ -617,12 +617,12 @@ def clean_mesh(self,obj): for edge in face.edges: if not edge.is_manifold and not edge.is_wire and not edge.is_boundary: invalid_edges += 1 - + if invalid_edges == len(face.edges): faces.append(face) bmesh.ops.delete(bm,geom=faces,context="FACES_ONLY") bmesh.update_edit_mesh(obj.data) - + def draw_verts(self,context,obj,bm,position,use_snap=False): scene = context.scene obj_matrix = obj.matrix_world @@ -632,16 +632,16 @@ def draw_verts(self,context,obj,bm,position,use_snap=False): snapped_pos, type, bm_ob = [self.mouse_pos_3d,None,None] if not use_snap: snapped_pos = position - + snapped_pos = self.limit_cursor_by_bounds(context,snapped_pos) - + for edge in bm.edges: edge.select = False for vert in bm.verts: vert.select = False for face in bm.faces: - face.select = False - + face.select = False + intersect_prev_vert = bm.select_history[0] if len(bm.select_history) > 0 else None for i,p in enumerate(self.intersection_points): for edge in bm.edges: @@ -655,7 +655,7 @@ def draw_verts(self,context,obj,bm,position,use_snap=False): if divider != 0: percentage = (obj.matrix_world @ sub_edge.verts[0].co - c).magnitude / (obj.matrix_world @ sub_edge.verts[0].co - obj.matrix_world @ sub_edge.verts[1].co).magnitude new_edge,new_vert = bmesh.utils.edge_split(sub_edge,sub_edge.verts[0],percentage) - + bm.select_history = [new_vert] try: edge = bm.edges.new([intersect_prev_vert,new_vert]) @@ -663,14 +663,14 @@ def draw_verts(self,context,obj,bm,position,use_snap=False): except: print("Edge already exists.") intersect_prev_vert = new_vert - + if type == "VERT" and use_snap: if self.contour_length > 0 and len(bm.select_history) > 0: new_vert = bm_ob try: edge = bm.edges.new([bm.select_history[0],new_vert]) self.new_added_edges.append(edge) - except: + except: print("Edge already exists.") bm.select_history = [new_vert] self.selected_vert_coord = obj_matrix @ new_vert.co @@ -680,11 +680,11 @@ def draw_verts(self,context,obj,bm,position,use_snap=False): bm.select_history = [new_vert] self.selected_vert_coord = obj_matrix @ new_vert.co new_vert.select = True - - - if self.contour_length == 0: + + + if self.contour_length == 0: self.contour_length += 1 - + elif type == "EDGE" and use_snap: sub_edge = bm_ob if sub_edge != None: @@ -706,36 +706,36 @@ def draw_verts(self,context,obj,bm,position,use_snap=False): #edge.select = True except: print("Edge already exists.") - - if self.contour_length == 0: + + if self.contour_length == 0: self.contour_length += 1 self.selected_vert_coord = obj_matrix @ new_vert.co - + else: new_vert = bm.verts.new(obj_matrix.inverted() @ snapped_pos) - + bmesh.update_edit_mesh(obj.data) - + if self.contour_length > 0 and len(bm.select_history) > 0: edge = bm.edges.new([bm.select_history[0],new_vert]) self.new_added_edges.append(edge) - + self.selected_vert_coord = obj_matrix @ new_vert.co new_vert.select = True bm.select_history = [new_vert] - + self.contour_length += 1 - + bmesh.update_edit_mesh(obj.data) - + def set_bone_shape_color_and_wireframe(self,context,obj): bm = bmesh.from_edit_mesh(obj.data) if len(bm.faces) > 0: self.armature.data.bones[self.bone.name].show_wire = False else: self.armature.data.bones[self.bone.name].show_wire = True - bm.free() - + bm.free() + def check_verts(self,context,event): verts = [] bm = bmesh.from_edit_mesh(context.active_object.data) @@ -745,8 +745,8 @@ def check_verts(self,context,event): for vert in verts: vert.co = context.active_object.matrix_world.inverted() @ self.limit_cursor_by_bounds(context,context.active_object.matrix_world @ vert.co) bmesh.update_edit_mesh(context.active_object.data) - - + + def get_selected_vert_pos(self,context): bm = bmesh.from_edit_mesh(context.active_object.data) for vert in bm.verts: @@ -755,12 +755,12 @@ def get_selected_vert_pos(self,context): return vert.co bmesh.update_edit_mesh(context.active_object.data) return None - + def check_selected_verts(self,context): bm = bmesh.from_edit_mesh(context.active_object.data) return bm.select_history - - + + def get_projected_point(self,edge,custom_pos=None,disable_edge_threshold=False): context = bpy.context obj = context.active_object @@ -771,46 +771,46 @@ def get_projected_point(self,edge,custom_pos=None,disable_edge_threshold=False): elif type(edge) == list: v1 = obj.matrix_world @ edge[0] v2 = obj.matrix_world @ edge[1] - + dist = min((v1-v2).magnitude * .5 , context.scene.coa_tools.snap_distance * context.space_data.region_3d.view_distance) if disable_edge_threshold: dist = 0 - + p1 = (v1 - v2).normalized() p2 = mouse_pos - v2 l = max(min(p2.dot(p1), (v1 - v2).magnitude - dist),0 + dist) c = (v2 + l * p1) return c - + def get_edge_slide_points(self,context,bm): obj = context.active_object - + snap_distance = context.scene.coa_tools.snap_distance * context.space_data.region_3d.view_distance - + edge_slide_points = [] for edge in bm.edges: bm.edges.ensure_lookup_table() if not edge.hide: vert_1 = obj.matrix_world @ edge.verts[0].co vert_2 = obj.matrix_world @ edge.verts[1].co - + left = min(vert_1.x , vert_2.x) - snap_distance right = max(vert_1.x , vert_2.x) + snap_distance top = max(vert_1.z , vert_2.z) + snap_distance bottom = min(vert_1.z , vert_2.z) - snap_distance - - if self.mouse_pos_3d.x > left and self.mouse_pos_3d.x < right and self.mouse_pos_3d.z < top and self.mouse_pos_3d.z > bottom: + + if self.mouse_pos_3d.x > left and self.mouse_pos_3d.x < right and self.mouse_pos_3d.z < top and self.mouse_pos_3d.z > bottom: c = self.get_projected_point(edge) edge_slide_points.append([c,edge]) - + return edge_slide_points - + def get_visible_verts(self,context,bm): obj = context.active_object visible_verts = [] self.selected_verts_count = 0 - - + + active_vert = None if len(bm.select_history)>0 and type(bm.select_history[0]) == bmesh.types.BMVert: active_vert = bm.select_history[0] @@ -820,7 +820,7 @@ def get_visible_verts(self,context,bm): if not vert.hide: visible_verts.append([obj.matrix_world @ vert.co , vert]) return visible_verts - + def snap_to_edge_or_vert(self,coord, get_bm_obj = False): obj = bpy.context.active_object context = bpy.context @@ -830,39 +830,39 @@ def snap_to_edge_or_vert(self,coord, get_bm_obj = False): point_type = None bm_obj2 = None verts_edges_data = None - + points = [] for e,edge in self.edge_slide_points: points.append([e,"EDGE",edge]) - + for p,vert in self.visible_verts: points.append([p,"VERT",vert]) - + for vert,type,bm_obj in points: - + if (vert - coord).magnitude < distance: if type == "VERT": distance = (vert - coord).magnitude snap_coord = vert point_type = type - + bm_obj2 = bm_obj if "Vert" in str(bm_obj): verts_edges_data = [bm_obj.co] elif "Edge" in str(bm_obj): verts_edges_data = [bm_obj.verts[0].co,bm_obj.verts[1].co] return [snap_coord , point_type , bm_obj2 , verts_edges_data] - + def get_intersecting_lines(self,coord,bm): scene = bpy.context.scene - + if scene.coa_tools.surface_snap: coord, point_type, bm_ob = self.snapped_vert_coord , self.point_type , self.bm_objs - else: + else: coord, point_type, bm_ob = [None,None,None] - + coord = self.limit_cursor_by_bounds(bpy.context,coord) - + intersection_points = [] if self.selected_vert_coord != None and coord != None: obj = bpy.context.active_object @@ -876,14 +876,14 @@ def get_intersecting_lines(self,coord,bm): if (ip - self.selected_vert_coord).magnitude > 0.001 and (ip - coord).magnitude > 0.001: intersection_points.append(ip) intersection_points.sort(key=lambda x: (self.selected_vert_coord - x).magnitude) - return intersection_points - + return intersection_points + def delete_geometry(self,context,bm,position,single_vert=False): obj = context.active_object snapped_vert_coord , point_type , bm_ob = self.snapped_vert_coord , self.point_type , self.bm_objs if point_type == "VERT": vert = bm_ob - + delete_verts = [vert] for edge in vert.link_edges: other_vert = edge.other_vert(vert) @@ -891,27 +891,27 @@ def delete_geometry(self,context,bm,position,single_vert=False): delete_verts.append(other_vert) for vert in delete_verts: bm.verts.remove(vert) - + elif point_type == "EDGE": edge = bm_ob - + verts = [] for vert in edge.verts: verts.append(vert) - - + + delete_edges = [edge] for edge in delete_edges: - bm.edges.remove(edge) - + bm.edges.remove(edge) + for vert in verts: if len(vert.link_edges) == 0: bm.verts.remove(vert) - + bm.verts.ensure_lookup_table() bm.edges.ensure_lookup_table() - - bmesh.update_edit_mesh(obj.data) + + bmesh.update_edit_mesh(obj.data) def suspend_area_fullscreen(self, context, event): if self.ctrl and event.type == "SPACE": @@ -940,15 +940,15 @@ def modal(self, context, event): self.shift = bool(event.shift) self.in_view_3d = functions.check_region(context, event) scene = context.scene - + ### map mouse button click_button = None select_button = None keyconfig = wm.keyconfigs.active click_button = 'LEFTMOUSE' select_button = 'RIGHTMOUSE' - - + + ### leave edit mode if context.active_object == None or (context.active_object != None and context.active_object.type == "MESH" and context.active_object.mode != "EDIT" and not self.draw_handler_removed) or self.sprite_object.coa_tools.edit_mesh == False or context.active_object.type != "MESH": return self.exit_edit_mode(context,event) @@ -963,9 +963,9 @@ def modal(self, context, event): ## skip everything if different tool is selected if functions.get_active_tool("EDIT_MESH") != "coa_tools.draw_polygon": return {'PASS_THROUGH'} - + if self.in_view_3d and context.active_object != None and self.type not in ["MIDDLEMOUSE"] and self.sprite_object.coa_tools.edit_mesh and click_button not in [select_button]: - ### set click drag + ### set click drag if self.type == click_button: self.click_drag = True if self.click_drag and self.value == "RELEASE": @@ -976,11 +976,11 @@ def modal(self, context, event): bpy.ops.ed.undo_push(message="Draw Contour") ### set mouse press history self.mouse_press_hist = self.mouse_press - + ### Cast Ray from mousePosition and set Cursor to hitPoint rayStart,rayEnd, ray = self.project_cursor(event) - - + + if rayEnd != None: pos = rayEnd pos[1] = obj.matrix_world.to_translation()[1]-0.00001 @@ -990,22 +990,22 @@ def modal(self, context, event): self.visible_verts = self.get_visible_verts(context,bm) if scene.coa_tools.surface_snap: self.edge_slide_points = self.get_edge_slide_points(context,bm) - + self.snapped_vert_coord, self.point_type, self.bm_objs, self.verts_edges_data = self.snap_to_edge_or_vert(self.mouse_pos_3d) else: self.snapped_vert_coord, self.point_type, self.bm_objs, self.verts_edges_data = [self.mouse_pos_3d,None,None,None] - + if self.contour_length > 0 and not self.alt: self.intersection_points = self.get_intersecting_lines(self.mouse_pos_3d,bm) else: self.intersection_points = [] - + self.snapped_vert_coord = self.limit_cursor_by_bounds(context, self.snapped_vert_coord) - - + + ### check if mouse is in 3d View coord = mathutils.Vector((event.mouse_region_x, event.mouse_region_y)) - + if coord[0] < 0 or coord[0] > bpy.context.area.width: self.inside_area = False bpy.context.window.cursor_set("DEFAULT") @@ -1014,7 +1014,7 @@ def modal(self, context, event): bpy.context.window.cursor_set("DEFAULT") else: self.inside_area = True - + if self.alt: bpy.context.window.cursor_set("CROSSHAIR") elif not self.alt and not self.shift: @@ -1022,29 +1022,29 @@ def modal(self, context, event): bpy.context.window.cursor_set("KNIFE") else: bpy.context.window.cursor_set("PAINT_BRUSH") - - + + ### Set Mouse click - + if (event.value == 'PRESS' or event.value == 'CLICK') and event.type == click_button and self.mouse_press == False and not self.ctrl and not self.shift: if not self.alt: self.mouse_press = True - + ### add vert on first mouse press self.cursor_pos_hist = Vector(self.mouse_pos_3d) self.draw_verts(context,obj,bm,self.cursor_pos_hist,use_snap=True) return{'RUNNING_MODAL'} - + if (event.value == 'RELEASE' and event.type == 'MOUSEMOVE'): self.mouse_press = False - - + + self.cur_distance = (self.mouse_pos_3d - self.cursor_pos_hist).magnitude self.draw_dir = (self.mouse_pos_3d - self.cursor_pos_hist).normalized() - + ### add verts while mouse is pressed and moved if not self.ctrl: if self.mouse_press and self.inside_area: @@ -1060,16 +1060,16 @@ def modal(self, context, event): ### check selected verts select_history = self.check_selected_verts(context) - - + + if self.type_prev in ["G"] and self.contour_length > 0: if len(select_history) > 0 and type(select_history[0]) == bmesh.types.BMVert: self.selected_vert_coord = obj.matrix_world @ select_history[0].co - + ### finishing edge drawing - if self.contour_length == 0 and len(self.new_added_edges) > 0: + if self.contour_length == 0 and len(self.new_added_edges) > 0: self.new_added_edges = [] - + scene.tool_settings.double_threshold = scene.coa_tools.snap_distance ### delete verts if self.alt and (self.click_drag or self.type == click_button) and not self.type in ["MIDDLEMOUSE"]: @@ -1080,20 +1080,20 @@ def modal(self, context, event): if self.shift and self.point_type == "EDGE": bpy.context.window.cursor_set("EYEDROPPER") if self.type == click_button: - + p1 = obj.matrix_world @ self.verts_edges_data[0] p2 = obj.matrix_world @ self.verts_edges_data[1] length = (p1-p2).magnitude scene.coa_tools.distance = length - + text = "Stroke Distance set to "+str(round(length,2)) self.report({"INFO"},text) - + ### remove last selected vert coord if nothing is selected if (self.selected_verts_count == 0 and self.selected_vert_coord != None) or self.type in [select_button] or (self.ctrl and self.type in ["Z"]):# or self.type_prev in ["G"]: self.selected_vert_coord = None self.contour_length = 0 - + ### deselect verts if event.type in ["ESC","RET"]: bm = bmesh.from_edit_mesh(context.active_object.data) @@ -1101,15 +1101,15 @@ def modal(self, context, event): for vert in bm.verts: vert.select = False for edge in bm.edges: - edge.select = False + edge.select = False for face in bm.faces: - face.select = False - - + face.select = False + + if (event.type in {'TAB'} and not event.ctrl): self.sprite_object.coa_tools.edit_mesh = False bpy.ops.object.mode_set(mode='OBJECT') - + self.type_prev = str(event.type) self.value_prev = str(event.value) except Exception as e: @@ -1117,7 +1117,7 @@ def modal(self, context, event): self.report({"ERROR"},"An Error occured, please check console for more Information.") self.exit_edit_mode(context,event,error=True) return {'PASS_THROUGH'} - + def exit_edit_mode(self,context,event,error=False): if not error: self.finish_edit_object(context) @@ -1125,7 +1125,7 @@ def exit_edit_mode(self,context,event,error=False): bpy.types.SpaceView3D.draw_handler_remove(self.draw_handler, "WINDOW") self.draw_handler = None # bpy.types.SpaceView3D.draw_handler_remove(self.draw_handler2, "WINDOW") - + self.draw_handler_removed = True self.sprite_object = functions.get_sprite_object(context.active_object) self.sprite_object.coa_tools.edit_mesh = False @@ -1183,7 +1183,7 @@ def exit_edit_mode(self,context,event,error=False): bpy.ops.object.mode_set(mode="OBJECT") context.view_layer.objects.active = obj return{'FINISHED'} - + _timer = 0 def prepare_edit_object(self, context): @@ -1270,50 +1270,50 @@ def execute(self, context): self.sprite_object = functions.get_sprite_object(context.active_object) if self.sprite_object != None: self.sprite_object = bpy.data.objects[self.sprite_object.name] - - + + self.armature = functions.get_armature(self.sprite_object) if self.armature != None: self.armature_pose_mode = self.armature.data.pose_position if self.mode == "EDIT_MESH": self.armature.data.pose_position = "REST" - - + + ### get Sprite Boundaries if self.texture_preview_object != None and self.texture_preview_object.type == "MESH": self.texture_preview_object.active_shape_key_index = 0 self.texture_preview_object.data.coa_tools.hide_base_sprite = False self.mesh_center , self.bounds = functions.get_bounds_and_center(self.texture_preview_object) - + if self.mode == "EDIT_MESH": #hide_base_sprite(bpy.context.active_object) self.edit_object.data.coa_tools.hide_base_sprite = True self.edit_object.active_shape_key_index = 0 - - + + if self.mode == "DRAW_BONE_SHAPE": self.draw_bounds = context.scene.coa_tools.lock_to_bounds context.scene.coa_tools.lock_to_bounds = False - + bone = bpy.context.active_pose_bone bone.use_custom_shape_bone_size = False armature = bpy.context.active_object #bone_mat = armature.matrix_world @ bone.matrix @ bone.matrix_basis.inverted() bone_mat = armature.matrix_local @ bone.matrix bone_loc, bone_rot, bone_scale = bone_mat.decompose() - + if bone.custom_shape != None and bone.custom_shape.name in bpy.data.objects: shape_name = bone.custom_shape.name - else: - shape_name = bone.name+"_custom_shape" - + else: + shape_name = bone.name+"_custom_shape" + if self.new_shape_name != "": obj = bpy.data.objects[self.new_shape_name] me = obj.data.copy() - else: + else: if shape_name in bpy.data.meshes: me = bpy.data.meshes[shape_name] - else: + else: me = bpy.data.meshes.new(shape_name) if shape_name in bpy.data.objects and self.new_shape_name == shape_name: bone_shape = bpy.data.objects[shape_name] @@ -1321,11 +1321,11 @@ def execute(self, context): if shape_name in bpy.data.objects: bone_shape = bpy.data.objects[shape_name] bone_shape.data = me - else: + else: bone_shape = bpy.data.objects.new(shape_name,me) self.edit_object = bone_shape self.edit_object_name = str(self.edit_object.name) - + bone_shape["coa_bone_shape"] = True context.collection.objects.link(bone_shape) context.view_layer.objects.active = bone_shape @@ -1333,7 +1333,7 @@ def execute(self, context): bone_shape.parent = self.sprite_object bone_shape.name = bone.name+"_custom_shape" me.name = bone.name+"_custom_shape" - + bone_shape.name = bone.name+"_custom_shape" bone_shape.matrix_local = bone_mat # scale = 1/bone_shape.dimensions.y @@ -1349,9 +1349,9 @@ def execute(self, context): if self.sprite_object != None: self.sprite_object.coa_tools.edit_mode = "MESH" self.sprite_object.coa_tools.edit_mesh = True - + wm = context.window_manager - + if self.mode == "EDIT_MESH": self.texture_preview_object.select_set(True) functions.set_local_view(True) @@ -1366,16 +1366,16 @@ def execute(self, context): args = () self.draw_handler = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_px, args, "WINDOW", "POST_PIXEL") # self.draw_handler2 = bpy.types.SpaceView3D.draw_handler_add(self.draw_callback_text, args, "WINDOW", "POST_PIXEL") - - bpy.ops.view3d.view_axis(type='FRONT', align_active=False, relative=False) + + bpy.ops.view3d.view_axis(type='FRONT', align_active=False, relative=False) #self._timer = wm.event_timer_add(0.1, window=context.window) - wm.modal_handler_add(self) + wm.modal_handler_add(self) #context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'} def cancel(self, context): return {'CANCELLED'} - + def draw_callback_text(self): obj = bpy.context.active_object ### draw text for edge length detection @@ -1524,7 +1524,7 @@ def draw_callback_px(self): self.draw_coords(coords=verts_loose, color=[1, 0, 0, 1], draw_type=CONSTANTS.DRAW_POINTS, point_size=8) self.draw_coords(coords=verts_loose_selected, color=[1, .8, .8, 1], draw_type=CONSTANTS.DRAW_POINTS, point_size=8) - + class COATOOLS_OT_PickEdgeLength(bpy.types.Operator): bl_idname = "coa_tools.pick_edge_length" @@ -1540,12 +1540,12 @@ def execute(self, context): scene = context.scene obj = context.active_object bm = bmesh.from_edit_mesh(obj.data) - + mult = 1 - + for edge in bm.edges: if edge.select: - #scene.coa_tools.distance = (obj.matrix_world @ (edge.verts[0].co - edge.verts[1].co)).magnitude/mult# edge.calc_length()/mult - scene.coa_tools.distance = ((edge.verts[0].co - edge.verts[1].co)).magnitude/mult# edge.calc_length()/mult - bmesh.update_edit_mesh(obj.data) + #scene.coa_tools.distance = (obj.matrix_world @ (edge.verts[0].co - edge.verts[1].co)).magnitude/mult# edge.calc_length()/mult + scene.coa_tools.distance = ((edge.verts[0].co - edge.verts[1].co)).magnitude/mult# edge.calc_length()/mult + bmesh.update_edit_mesh(obj.data) return {"FINISHED"} From 32a8ed22a14a316aa4889a4d29b837e80fa8e194 Mon Sep 17 00:00:00 2001 From: kreezii Date: Sun, 6 Dec 2020 19:49:16 +0100 Subject: [PATCH 7/7] Fix error when pressing ALT key in Edit Armature mode. --- Blender/coa_tools/functions.py | 198 ++++++++++++++++----------------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/Blender/coa_tools/functions.py b/Blender/coa_tools/functions.py index 72189e2..b1a5379 100644 --- a/Blender/coa_tools/functions.py +++ b/Blender/coa_tools/functions.py @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . ''' - + import bpy import bpy_extras import bpy_extras.view3d_utils @@ -54,7 +54,7 @@ def set_uv_image(obj): if len(data.materials) > 0: mat = data.materials[0] tex = [slot.texture for slot in mat.texture_slots if slot != None and slot.texture.type == "IMAGE"][0] - img = tex.image if tex.image != None else None + img = tex.image if tex.image != None else None if img != None: for uv_vert in obj.data.uv_textures[0].data: uv_vert.image = img @@ -66,7 +66,7 @@ def draw_sculpt_ui(self,context,layout): toolsettings = context.tool_settings settings = toolsettings.sculpt brush = settings.brush - + col = layout.column(align=True) col.separator() if obj.data.shape_keys == None: @@ -74,11 +74,11 @@ def draw_sculpt_ui(self,context,layout): subrow = col.row(align=True) subrow.prop(obj.coa_tools,"selected_shapekey",text="") op = subrow.operator("coa_tools.shapekey_add",icon="FILE_NEW",text="") - + if obj.data.shape_keys != None and len(obj.data.shape_keys.key_blocks) > 0: op = subrow.operator("coa_tools.shapekey_rename",icon="OUTLINER_DATA_FONT",text="") op = subrow.operator("coa_tools.shapekey_remove",icon="X",text="") - + if obj.data.shape_keys != None: shapekey_index = int(obj.coa_tools.selected_shapekey) if shapekey_index > 0: @@ -87,40 +87,40 @@ def draw_sculpt_ui(self,context,layout): subrow.prop(active_shapekey,"value") subrow.prop(obj,"show_only_shape_key", text="",icon="UNPINNED") - + col = layout.column(align=False) subrow = col.row(align=True) subrow.prop(obj,"show_wire",toggle=True,icon="MESH_DATA") subrow.prop(obj,"show_all_edges",toggle=True) - + if not context.particle_edit_object: col = layout.split().column() col.template_ID_preview(settings, "brush", new="brush.add", rows=3, cols=8) - + row = layout.row(align=True) settings = toolsettings.unified_paint_settings if toolsettings.unified_paint_settings.use_unified_size else toolsettings.sculpt.brush - + if settings.use_locked_size: icon = "UNLOCKED" elif not settings.use_locked_size: icon = "LOCKED" - + col = layout.column(align=True) - - subrow = col.row(align=True) + + subrow = col.row(align=True) subrow.prop(settings,"use_locked_size",text="",toggle=True,icon=icon) - subrow.prop(settings,"size",slider=True) + subrow.prop(settings,"size",slider=True) subrow.prop(settings,"use_unified_size",text="") col.prop(settings,"strength") - - + + row = layout.row(align=True) row.label(text="Symmetry:") row = layout.row(align=True) row.prop(toolsettings.sculpt,"use_symmetry_x",text="X",toggle=True) row.prop(toolsettings.sculpt,"use_symmetry_y",text="Y",toggle=True) row.prop(toolsettings.sculpt,"use_symmetry_z",text="Z",toggle=True) - + brush = toolsettings.sculpt.brush @@ -134,7 +134,7 @@ def draw_sculpt_ui(self,context,layout): row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP' row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE' row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX' - + def operator_exists(idname): op_name = idname.split(".") @@ -146,7 +146,7 @@ def remove_base_mesh(obj): bm = bmesh.from_edit_mesh(obj.data) bm.verts.ensure_lookup_table() verts = [] - + if "coa_base_sprite" in obj.vertex_groups: v_group_idx = obj.vertex_groups["coa_base_sprite"].index for i,vert in enumerate(obj.data.vertices): @@ -156,19 +156,19 @@ def remove_base_mesh(obj): break bmesh.ops.delete(bm,geom=verts,context=1) - bm = bmesh.update_edit_mesh(obj.data) + bm = bmesh.update_edit_mesh(obj.data) bpy.ops.object.mode_set(mode="OBJECT") def fix_bone_roll(armature): mode = armature.mode bpy.ops.object.mode_set(mode="EDIT") - + ### show all bone layers layers = [] for i,layer in enumerate(armature.data.layers): layers.append(layer) armature.data.layers[i] = True - + ### store bone selection and store intial state hidden_bones = [] locked_bones = [] @@ -177,45 +177,45 @@ def fix_bone_roll(armature): if bone.hide: hidden_bones.append(bone) bone.hide = False - + if bone.hide_select: - locked_bones.append(bone) + locked_bones.append(bone) bone.hide_select = False - + if bone.select and bone.select_head and bone.select_tail: selected_edit_bones.append(bone) - + bone.select = True bone.select_head = True bone.select_tail = True - - ### align bone roll + + ### align bone roll bpy.ops.armature.calculate_roll(type='GLOBAL_POS_Y') - + ### restore bone selection, hide and hide_select for bone in armature.data.edit_bones: if bone in hidden_bones: bone.hide = True if bone in locked_bones: - bone.hide_select = True - + bone.hide_select = True + if bone not in selected_edit_bones: bone.select = False bone.select_head = False bone.select_tail = False - + ### restore bone layer visibility for i,layer in enumerate(layers): armature.data.layers[i] = layer - - ### change back to previous mode + + ### change back to previous mode bpy.ops.object.mode_set(mode=mode) - + def set_weights(self,context,obj): if len(context.selected_bones) == 0: return {'RUNNING_MODAL'} - + self.set_waits = True bone_data = [] orig_armature = self.armature#context.active_object @@ -223,11 +223,11 @@ def set_weights(self,context,obj): for weight in obj.vertex_groups: if weight.name in orig_armature.data.bones: obj.vertex_groups.remove(weight) - ### + ### use_deform = [] bone_pos = {} selected_bones = [] - + for i,bone in enumerate(orig_armature.data.edit_bones): if bone.select and (bone.select_head or bone.select_tail): selected_bones.append(bone) @@ -241,15 +241,15 @@ def set_weights(self,context,obj): orig_armature.data.bones[i].use_deform = False orig_armature.select_set(True) obj.select_set(True) - + #return{'FINISHED'} - + parent = bpy.data.objects[obj.parent.name] obj_orig_location = Vector(obj.location) obj.location[1] = 0.00001 bpy.ops.object.parent_set(type='ARMATURE_AUTO') obj.location = obj_orig_location - + for bone in bone_pos: bone.tail[1] = bone_pos[bone]["tail"] bone.head[1] = bone_pos[bone]["head"] @@ -269,11 +269,11 @@ def set_weights(self,context,obj): orig_armature.select_set(True) context.view_layer.objects.active = orig_armature obj.select_set(False) - + bpy.ops.object.mode_set(mode='EDIT') self.set_waits = False - - return {'RUNNING_MODAL'} + + return {'RUNNING_MODAL'} def hide_base_sprite(obj): context = bpy.context @@ -315,28 +315,28 @@ def hide_base_sprite(obj): bmesh.update_edit_mesh(me) bpy.ops.object.mode_set(mode=orig_mode) context.view_layer.objects.active = selected_object - + def get_uv_from_vert(uv_layer, v): for l in v.link_loops: if v.select: uv_data = l[uv_layer] return uv_data - + def update_uv_unwrap(context): obj = context.active_object me = obj.data bm = bmesh.from_edit_mesh(me) - + ### pin uv boundary vertex uv_layer = bm.loops.layers.uv.active for vert in bm.verts: - + uv_vert = get_uv_from_vert(uv_layer, vert) if uv_vert != None: pass - bmesh.update_edit_mesh(me) - + bmesh.update_edit_mesh(me) + def clamp(n, minn, maxn): @@ -380,7 +380,7 @@ def unwrap_with_bounds(obj,uv_idx): uv_data = l[uv_layer] uv_data.uv[0] = (bm.verts[i].co[0] * scale_x) - offset[0] uv_data.uv[1] = (bm.verts[i].co[2] * scale_z)+1 - offset[1] - + bmesh.update_edit_mesh(me) bm.free() bpy.ops.object.mode_set(mode="OBJECT") @@ -391,7 +391,7 @@ def get_local_dimension(obj): x1 = -10000000000 * 10000000000 y0 = 10000000000 * 10000000000 y1 = -100000000000 * 10000000000 - + for vert in obj.data.vertices: if vert.co[0] < x0: x0 = vert.co[0] @@ -401,7 +401,7 @@ def get_local_dimension(obj): y0 = vert.co[2] if vert.co[2] > y1: y1 = vert.co[2] - + offset = [x0, y1] return [(x1-x0), (y1 - y0), offset] @@ -432,22 +432,22 @@ def check_name(name_array,name): def create_action(context,item=None,obj=None): sprite_object = get_sprite_object(context.active_object) - + if len(sprite_object.coa_tools.anim_collections) < 3: bpy.ops.coa_tools.add_animation_collection() - + if item == None: item = sprite_object.coa_tools.anim_collections[sprite_object.coa_tools.anim_collections_index] if obj == None: obj = context.active_object - + action_name = item.name + "_" + obj.name - + if action_name not in bpy.data.actions: action = bpy.data.actions.new(action_name) else: action = bpy.data.actions[action_name] - + action.use_fake_user = True if obj.animation_data == None: obj.animation_data_create() @@ -473,13 +473,13 @@ def set_direction(obj): else: if obj.scale.x < 0: obj.scale.x *= -1 - + def set_action(context,item=None): sprite_object = get_sprite_object(context.active_object) if item == None: index = min(len(sprite_object.coa_tools.anim_collections) - 1, sprite_object.coa_tools.anim_collections_index) item = sprite_object.coa_tools.anim_collections[index] - + children = get_children(context,sprite_object,ob_list=[]) animation_objects = [] @@ -492,7 +492,7 @@ def set_action(context,item=None): clear_pose(child) if child.animation_data != None: child.animation_data.action = None - + if child.type == "ARMATURE" and item.name == "Restpose": for bone in child.pose.bones: bone.scale = Vector((1,1,1)) @@ -507,8 +507,8 @@ def set_action(context,item=None): action = None if action_name in bpy.data.actions: action = bpy.data.actions[action_name] - if action != None: - action.use_fake_user = True + if action != None: + action.use_fake_user = True if child.animation_data == None: child.animation_data_create() child.animation_data.action = action @@ -534,7 +534,7 @@ def set_local_view(local): else: if area.spaces.active.local_view != None: bpy.ops.view3d.localview(override) - + def actions_callback(self,context): actions = [] @@ -550,7 +550,7 @@ def create_armature(context): obj = bpy.context.active_object sprite_object = get_sprite_object(obj) armature = get_armature(sprite_object) - + if armature != None: context.view_layer.objects.active = armature armature.select = True @@ -573,10 +573,10 @@ def lock_view(screen, lock): if space.type == "VIEW_3D": region = space.region_3d if lock: - region.view_rotation = Quaternion((0.7071,0.7071,-0.0,-0.0)) + region.view_rotation = Quaternion((0.7071,0.7071,-0.0,-0.0)) region.lock_rotation = True else: - region.lock_rotation = False + region.lock_rotation = False def set_view(scene,mode): @@ -609,11 +609,11 @@ def set_view(scene,mode): def set_middle_mouse_move(enable): km = bpy.context.window_manager.keyconfigs.addon.keymaps["3D View"] km.keymap_items["view3d.move"].active = enable - + def assign_tex_to_uv(image,uv): for i,data in enumerate(uv.data): uv.data[i].image = image - + def set_bone_group(self, armature, pose_bone,group = "ik_group" ,theme = "THEME09"): new_group = None if group not in armature.pose.bone_groups: @@ -623,10 +623,10 @@ def set_bone_group(self, armature, pose_bone,group = "ik_group" ,theme = "THEME0 new_group = armature.pose.bone_groups[group] pose_bone.bone_group = new_group -last_sprite_object = None +last_sprite_object = None def get_sprite_object(obj): global last_sprite_object - + context = bpy.context if obj != None: if "sprite_object" in obj.coa_tools: @@ -634,19 +634,19 @@ def get_sprite_object(obj): return obj elif obj.parent != None: return get_sprite_object(obj.parent) - + if last_sprite_object != None and last_sprite_object in bpy.data.objects: return bpy.data.objects[last_sprite_object] - return None - + return None + def get_armature(obj): if obj != None and obj.type != "ARMATURE": for child in obj.children: if child.type == "ARMATURE": return child else: - return obj - return None + return obj + return None def get_bounds_and_center(obj): sprite_center = Vector((0,0,0)) @@ -658,26 +658,26 @@ def get_bounds_and_center(obj): bounds.append(world_corner) sprite_center = sprite_center * 0.125 return[sprite_center,bounds] - - + + def ray_cast(start,end,list=[]): end = end - start - result = bpy.context.scene.ray_cast(bpy.context.view_layer, start, end) + result = bpy.context.scene.ray_cast(bpy.context.view_layer.depsgraph, start, end) result = [result[0],result[4],result[5],result[1],result[2]] - + if result[0]: if result not in list: list.append(result) else: - return list - + return list + dir_vec = (end - start).normalized() new_start = result[3] + (dir_vec * 0.000001) return ray_cast(new_start,end,list) else: return list - + def lock_sprites(context, obj, lock): for child in obj.children: if child.type == "MESH": @@ -687,10 +687,10 @@ def lock_sprites(context, obj, lock): if child == context.view_layer.objects.active: context.view_layer.objects.active = child.parent else: - child.hide_select = False + child.hide_select = False if len(child.children) > 0: return lock_sprites(context,child,lock) - return + return def get_children(context,obj,ob_list=[]): @@ -739,7 +739,7 @@ def change_slot_mesh_data(context, obj, obj_eval=None): if obj_eval == None: obj_eval = obj idx = max(min(obj_eval.coa_tools.slot_index,len(obj.coa_tools.slot)-1),0) - + slot = obj.coa_tools.slot[idx] obj = slot.id_data obj.data = slot.mesh @@ -748,7 +748,7 @@ def change_slot_mesh_data(context, obj, obj_eval=None): if slot != slot2: slot2["active"] = False else: - slot2["active"] = True + slot2["active"] = True if "coa_base_sprite" in obj.modifiers: if slot.mesh.coa_tools.hide_base_sprite: obj.modifiers["coa_base_sprite"].show_render = True @@ -778,7 +778,7 @@ def display_children(self, context, obj): sprite_object = get_sprite_object(obj) children = get_children(context,sprite_object,ob_list=[]) armature = get_armature(sprite_object) - + list1 = [] list2 = [] for child in children: @@ -796,9 +796,9 @@ def display_children(self, context, obj): row.prop(sprite_object.coa_tools, "favorite",text="",icon="SOLO_ON") else: row.prop(sprite_object.coa_tools, "favorite",text="",icon="SOLO_OFF") - + col = box.column(align=True) - + current_display_item = 0 ### Sprite Objects display for all that are in active Scene disable_list = sprite_object.coa_tools.edit_mesh or sprite_object.coa_tools.edit_armature or sprite_object.coa_tools.edit_weights or sprite_object.coa_tools.edit_shapekey @@ -806,7 +806,7 @@ def display_children(self, context, obj): for obj2 in context.view_layer.objects: if get_sprite_object(obj2) == obj2: in_range = current_display_item in range(context.scene.coa_tools.display_page * context.scene.coa_tools.display_length , context.scene.coa_tools.display_page * context.scene.coa_tools.display_length + context.scene.coa_tools.display_length) - + if in_range or context.scene.coa_tools.display_all: row = col.row(align=True) subrow = row.row(align=True) @@ -840,34 +840,34 @@ def display_children(self, context, obj): op = subrow.operator("coa_tools.view_sprite",icon="ZOOM_SELECTED",text="",emboss=False) op.type = "VIEW_ALL" op.name = obj2.name - + row2 = subrow.row() if not obj2.coa_tools.change_z_ordering: row2.active = False row2.prop(obj2.coa_tools,"change_z_ordering",text="",icon="SORTALPHA",emboss=False) - + current_display_item += 1 if obj2 == sprite_object: draw_children(self, context, sprite_object, layout, box, row, col, children, obj, current_display_item, disable_list) - + def favorite_bones(armature): for bone in armature.data.bones: if bone.coa_tools.favorite: return True return False - + def filter_bone_name(armature,filter): for bone in armature.data.bones: if filter.upper() in bone.name.upper(): return True return False -def draw_children(self,context,sprite_object,layout,box,row,col,children,obj,current_display_item, disable_list): +def draw_children(self,context,sprite_object,layout,box,row,col,children,obj,current_display_item, disable_list): obj = get_sprite_object(obj) active_collection = bpy.data.collections[context.scene.coa_tools.active_collection] ### Sprite Object Children Display - + if disable_list: if sprite_object.coa_tools.edit_mesh: box.row().prop(sprite_object.coa_tools, "edit_mesh", text="", toggle=True, icon="LOOP_BACK") @@ -878,8 +878,8 @@ def draw_children(self,context,sprite_object,layout,box,row,col,children,obj,cur if sprite_object.coa_tools.edit_shapekey: box.row().prop(sprite_object.coa_tools, "edit_shapekey", text="", toggle=True, icon="LOOP_BACK") - - + + if sprite_object != None and sprite_object.coa_tools.show_children: children = sorted(children, key=lambda x: x.location[1] if type(x) == bpy.types.Object else x.name,reverse=False) children = sorted(children, key=lambda x: x.type if type(x) == bpy.types.Object else x.name,reverse=False) @@ -1040,7 +1040,7 @@ def draw_bone_entry(self,bone,row,col,child,indentation_level=0): row.separator() icon = "LAYER_USED" if bone.select: - icon = "LAYER_ACTIVE" + icon = "LAYER_ACTIVE" row.label(text="",icon=icon) row.label(text="",icon="BONE_DATA") bone_name = ""+bone.name