import bpy import bmesh import operator from mathutils import Vector from collections import defaultdict from math import pi from . import utilities_uv from . import utilities_ui from . import utilities_texel name_texture = "TT_resize_area" utilities_ui.icon_register("op_extend_canvas_TL_active.png") utilities_ui.icon_register("op_extend_canvas_TR_active.png") utilities_ui.icon_register("op_extend_canvas_BL_active.png") utilities_ui.icon_register("op_extend_canvas_BR_active.png") def on_dropdown_size_x(self, context): self.size_x = int(self.dropdown_size_x) # context.area.tag_redraw() def on_dropdown_size_y(self, context): self.size_y = int(self.dropdown_size_y) # context.area.tag_redraw() class op(bpy.types.Operator): bl_idname = "uv.textools_uv_resize" bl_label = "Resize Area" bl_description = "Resize or extend the UV area" bl_options = {'REGISTER', 'UNDO'} size_x: bpy.props.IntProperty( name="Width", description="padding size in pixels", default=1024, min=1, max=8192 ) size_y: bpy.props.IntProperty( name="Height", description="padding size in pixels", default=1024, min=1, max=8192 ) dropdown_size_x: bpy.props.EnumProperty( items=utilities_ui.size_textures, name="", update=on_dropdown_size_x, default='1024' ) dropdown_size_y: bpy.props.EnumProperty( items=utilities_ui.size_textures, name="", update=on_dropdown_size_y, default='1024' ) direction: bpy.props.EnumProperty(name='direction', items=( ('TL', ' ', 'Top Left', utilities_ui.icon_get( "op_extend_canvas_TL_active"), 0), ('BL', ' ', 'Bottom Left', utilities_ui.icon_get( "op_extend_canvas_BL_active"), 2), ('TR', ' ', 'Top Right', utilities_ui.icon_get( "op_extend_canvas_TR_active"), 1), ('BR', ' ', 'Bottom Right', utilities_ui.icon_get( "op_extend_canvas_BR_active"), 3) )) @classmethod def poll(cls, context): if not bpy.context.active_object: return False if bpy.context.active_object.type != 'MESH': return False # Only in Edit mode if bpy.context.active_object.mode != 'EDIT': return False # Only in UV editor mode if bpy.context.area.type != 'IMAGE_EDITOR': return False # Requires UV map if not bpy.context.object.data.uv_layers: return False return True def invoke(self, context, event): print("Invoke resize area") self.size_x = bpy.context.scene.texToolsSettings.size[0] self.size_y = bpy.context.scene.texToolsSettings.size[1] for item in utilities_ui.size_textures: if int(item[0]) == self.size_x: self.dropdown_size_x = item[0] break for item in utilities_ui.size_textures: if int(item[0]) == self.size_y: self.dropdown_size_y = item[0] break return context.window_manager.invoke_props_dialog(self, width=140) def check(self, context): return True def draw(self, context): # https://b3d.interplanety.org/en/creating-pop-up-panels-with-user-ui-in-blender-add-on/ layout = self.layout layout.separator() # New Size row = layout.row() split = row.split(factor=0.6) c = split.column(align=True) c.prop(self, "size_x", text="X", expand=True) c.prop(self, "size_y", text="Y", expand=True) c = split.column(align=True) c.prop(self, "dropdown_size_x", text="") c.prop(self, "dropdown_size_y", text="") # Direction col = layout.column(align=True) col.label(text="Direction") row = col.row(align=True) row.prop(self, 'direction', expand=True) # Summary size_A = "{} x {}".format( bpy.context.scene.texToolsSettings.size[0], bpy.context.scene.texToolsSettings.size[1]) if bpy.context.scene.texToolsSettings.size[0] == bpy.context.scene.texToolsSettings.size[1]: size_A = "{}²".format(bpy.context.scene.texToolsSettings.size[0]) size_B = "{} x {}".format(self.size_x, self.size_y) if self.size_x == self.size_y: size_B = "{}²".format(self.size_x) layout.label(text="{} to {}".format( size_A, size_B )) layout.separator() def execute(self, context): # Store selection utilities_uv.selection_store() # Get start and end size size_A = Vector([ bpy.context.scene.texToolsSettings.size[0], bpy.context.scene.texToolsSettings.size[1] ]) size_B = Vector([ self.size_x, self.size_y ]) resize_uv( self, context, self.direction, size_A, size_B ) resize_image( context, self.direction, size_A, size_B ) bpy.context.scene.texToolsSettings.size[0] = self.size_x bpy.context.scene.texToolsSettings.size[1] = self.size_y # Restore selection utilities_uv.selection_restore() return {'FINISHED'} def resize_uv(self, context, mode, size_A, size_B): # Set pivot bpy.context.tool_settings.transform_pivot_point = 'CURSOR' if mode == 'TL': bpy.ops.uv.cursor_set(location=Vector([0, 1])) elif mode == 'TR': bpy.ops.uv.cursor_set(location=Vector([1, 1])) elif mode == 'BL': bpy.ops.uv.cursor_set(location=Vector([0, 0])) elif mode == 'BR': bpy.ops.uv.cursor_set(location=Vector([1, 0])) # Select all UV faces bpy.ops.uv.select_all(action='SELECT') # Resize scale_x = size_A.x / size_B.x scale_y = size_A.y / size_B.y bpy.ops.transform.resize( value=(scale_x, scale_y, 1.0), use_proportional_edit=False) def resize_image(context, mode, size_A, size_B): print("resize image {}".format(context.area.spaces)) # Notes: https://blender.stackexchange.com/questions/31514/active-image-of-uv-image-editor # https://docs.blender.org/api/blender_python_api_2_70_4/bpy.types.SpaceImageEditor.html if context.area.spaces.active != None: if context.area.spaces.active.image != None: image = context.area.spaces.active.image image_obj = utilities_texel.get_object_texture_image( bpy.context.active_object) if name_texture in image.name or image == image_obj: # Resize Image UV editor background image utilities_texel.image_resize( image, int(size_B.x), int(size_B.y)) else: # No Image assigned # Get background color from theme + 1.25x brighter theme = bpy.context.preferences.themes[0] color = theme.image_editor.space.back.copy() color.r *= 1.15 color.g *= 1.15 color.b *= 1.15 image = None if name_texture in bpy.data.images: # TexTools Image already exists image = bpy.data.images[name_texture] image.scale(int(size_B.x), int(size_B.y)) image.generated_width = int(size_B.x) image.generated_height = int(size_B.y) else: # Create new image image = bpy.data.images.new( name_texture, width=int(size_B.x), height=int(size_B.y)) image.generated_color = (color.r, color.g, color.b, 1.0) image.generated_type = 'BLANK' image.generated_width = int(size_B.x) image.generated_height = int(size_B.y) # Assign in UV view context.area.spaces.active.image = image # Clean up images and materials utilities_texel.checker_images_cleanup() bpy.utils.register_class(op)