diff options
author | Nutti <nutti.metro@gmail.com> | 2017-11-19 09:35:57 +0300 |
---|---|---|
committer | Nutti <nutti.metro@gmail.com> | 2017-11-19 09:35:57 +0300 |
commit | 85a2b50e0e3d505f702a172efc0befa46e87d853 (patch) | |
tree | 3e93434e0f9e18a53f2384f0f9da96952614179d | |
parent | c21b887882e6dd51abdab678e4ebadf9ed483077 (diff) |
Magic UV: release v4.5
-rw-r--r-- | uv_magic_uv/__init__.py | 14 | ||||
-rw-r--r-- | uv_magic_uv/muv_common.py | 12 | ||||
-rw-r--r-- | uv_magic_uv/muv_cpuv_ops.py | 29 | ||||
-rw-r--r-- | uv_magic_uv/muv_cpuv_selseq_ops.py | 25 | ||||
-rw-r--r-- | uv_magic_uv/muv_fliprot_ops.py | 15 | ||||
-rw-r--r-- | uv_magic_uv/muv_menu.py | 21 | ||||
-rw-r--r-- | uv_magic_uv/muv_mirroruv_ops.py | 10 | ||||
-rw-r--r-- | uv_magic_uv/muv_mvuv_ops.py | 4 | ||||
-rw-r--r-- | uv_magic_uv/muv_packuv_ops.py | 14 | ||||
-rw-r--r-- | uv_magic_uv/muv_preferences.py | 12 | ||||
-rw-r--r-- | uv_magic_uv/muv_preserve_uv_aspect.py | 117 | ||||
-rw-r--r-- | uv_magic_uv/muv_props.py | 12 | ||||
-rw-r--r-- | uv_magic_uv/muv_texlock_ops.py | 10 | ||||
-rw-r--r-- | uv_magic_uv/muv_texproj_ops.py | 4 | ||||
-rw-r--r-- | uv_magic_uv/muv_transuv_ops.py | 76 | ||||
-rw-r--r-- | uv_magic_uv/muv_unwrapconst_ops.py | 12 | ||||
-rw-r--r-- | uv_magic_uv/muv_uvbb_ops.py | 45 | ||||
-rw-r--r-- | uv_magic_uv/muv_uvw_ops.py | 222 | ||||
-rw-r--r-- | uv_magic_uv/muv_wsuv_ops.py | 165 |
19 files changed, 640 insertions, 179 deletions
diff --git a/uv_magic_uv/__init__.py b/uv_magic_uv/__init__.py index 6b9b6d2b..171a5ac4 100644 --- a/uv_magic_uv/__init__.py +++ b/uv_magic_uv/__init__.py @@ -20,15 +20,15 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" bl_info = { "name": "Magic UV", "author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, " - "Keith (Wahooney) Boshoff, McBuff, MaxRobinot", - "version": (4, 4, 0), + "Keith (Wahooney) Boshoff, McBuff, MaxRobinot, Alexander Milovsky", + "version": (4, 5, 0), "blender": (2, 79, 0), "location": "See Add-ons Preferences", "description": "UV Manipulator Tools. See Add-ons Preferences for details", @@ -59,6 +59,7 @@ if "bpy" in locals(): importlib.reload(muv_wsuv_ops) importlib.reload(muv_unwrapconst_ops) importlib.reload(muv_preserve_uv_aspect) + importlib.reload(muv_uvw_ops) else: from . import muv_preferences from . import muv_menu @@ -77,6 +78,7 @@ else: from . import muv_wsuv_ops from . import muv_unwrapconst_ops from . import muv_preserve_uv_aspect + from . import muv_uvw_ops import bpy @@ -84,7 +86,8 @@ import bpy def view3d_uvmap_menu_fn(self, context): self.layout.separator() self.layout.menu(muv_menu.MUV_CPUVMenu.bl_idname, icon="IMAGE_COL") - self.layout.operator(muv_fliprot_ops.MUV_FlipRot.bl_idname, icon="IMAGE_COL") + self.layout.operator( + muv_fliprot_ops.MUV_FlipRot.bl_idname, icon="IMAGE_COL") self.layout.menu(muv_menu.MUV_TransUVMenu.bl_idname, icon="IMAGE_COL") self.layout.operator(muv_mvuv_ops.MUV_MVUV.bl_idname, icon="IMAGE_COL") self.layout.menu(muv_menu.MUV_TexLockMenu.bl_idname, icon="IMAGE_COL") @@ -96,6 +99,7 @@ def view3d_uvmap_menu_fn(self, context): self.layout.menu( muv_preserve_uv_aspect.MUV_PreserveUVAspectMenu.bl_idname, icon='IMAGE_COL') + self.layout.menu(muv_menu.MUV_UVWMenu.bl_idname, icon="IMAGE_COL") def image_uvs_menu_fn(self, context): diff --git a/uv_magic_uv/muv_common.py b/uv_magic_uv/muv_common.py index ff2fe3f0..b52971ec 100644 --- a/uv_magic_uv/muv_common.py +++ b/uv_magic_uv/muv_common.py @@ -20,8 +20,8 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy from . import muv_props @@ -45,11 +45,9 @@ def check_version(major, minor, _): return 0 if bpy.app.version[0] > major: return 1 - else: - if bpy.app.version[1] > minor: - return 1 - else: - return -1 + if bpy.app.version[1] > minor: + return 1 + return -1 def redraw_all_areas(): diff --git a/uv_magic_uv/muv_cpuv_ops.py b/uv_magic_uv/muv_cpuv_ops.py index c3e0e6a3..82f043c6 100644 --- a/uv_magic_uv/muv_cpuv_ops.py +++ b/uv_magic_uv/muv_cpuv_ops.py @@ -20,17 +20,17 @@ __author__ = "Nutti <nutti.metro@gmail.com>, Jace Priester" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy import bmesh from bpy.props import ( - StringProperty, - BoolProperty, - IntProperty, - EnumProperty, - ) + StringProperty, + BoolProperty, + IntProperty, + EnumProperty, +) from . import muv_common @@ -85,11 +85,11 @@ class MUV_CPUVCopyUV(bpy.types.Operator): if face.select: uvs = [l[uv_layer].uv.copy() for l in face.loops] pin_uvs = [l[uv_layer].pin_uv for l in face.loops] - seams = [l.edge.seam for l in face.loops] + seams = [l.edge.seam for l in face.loops] props.src_uvs.append(uvs) props.src_pin_uvs.append(pin_uvs) props.src_seams.append(seams) - if len(props.src_uvs) == 0 or len(props.src_pin_uvs) == 0: + if not props.src_uvs or not props.src_pin_uvs: self.report({'WARNING'}, "No faces are selected") return {'CANCELLED'} self.report({'INFO'}, "%d face(s) are selected" % len(props.src_uvs)) @@ -164,7 +164,7 @@ class MUV_CPUVPasteUV(bpy.types.Operator): def execute(self, context): props = context.scene.muv_props.cpuv - if len(props.src_uvs) == 0 or len(props.src_pin_uvs) == 0: + if not props.src_uvs or not props.src_pin_uvs: self.report({'WARNING'}, "Need copy UV at first") return {'CANCELLED'} if self.uv_map == "": @@ -201,7 +201,7 @@ class MUV_CPUVPasteUV(bpy.types.Operator): dest_uvs.append(uvs) dest_pin_uvs.append(pin_uvs) dest_seams.append(seams) - if len(dest_uvs) == 0 or len(dest_pin_uvs) == 0: + if not dest_uvs or not dest_pin_uvs: self.report({'WARNING'}, "No faces are selected") return {'CANCELLED'} if self.strategy == 'N_N' and len(props.src_uvs) != len(dest_uvs): @@ -248,7 +248,8 @@ class MUV_CPUVPasteUV(bpy.types.Operator): spuvs_fr.insert(0, pin_uv) ss_fr.insert(0, s) # paste UVs - for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr, spuvs_fr, ss_fr): + for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr, + spuvs_fr, ss_fr): l[uv_layer].uv = suv l[uv_layer].pin_uv = spuv if self.copy_seams is True: @@ -331,7 +332,7 @@ class MUV_CPUVObjCopyUV(bpy.types.Operator): for face in bm.faces: uvs = [l[uv_layer].uv.copy() for l in face.loops] pin_uvs = [l[uv_layer].pin_uv for l in face.loops] - seams = [l.edge.seam for l in face.loops] + seams = [l.edge.seam for l in face.loops] props.src_uvs.append(uvs) props.src_pin_uvs.append(pin_uvs) props.src_seams.append(seams) @@ -383,7 +384,7 @@ class MUV_CPUVObjPasteUV(bpy.types.Operator): @memorize_view_3d_mode def execute(self, context): props = context.scene.muv_props.cpuv_obj - if len(props.src_uvs) == 0 or len(props.src_pin_uvs) == 0: + if not props.src_uvs or not props.src_pin_uvs: self.report({'WARNING'}, "Need copy UV at first") return {'CANCELLED'} diff --git a/uv_magic_uv/muv_cpuv_selseq_ops.py b/uv_magic_uv/muv_cpuv_selseq_ops.py index 5a1154a9..3cf69ff7 100644 --- a/uv_magic_uv/muv_cpuv_selseq_ops.py +++ b/uv_magic_uv/muv_cpuv_selseq_ops.py @@ -20,17 +20,17 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy import bmesh from bpy.props import ( - StringProperty, - BoolProperty, - IntProperty, - EnumProperty, - ) + StringProperty, + BoolProperty, + IntProperty, + EnumProperty, +) from . import muv_common @@ -78,11 +78,11 @@ class MUV_CPUVSelSeqCopyUV(bpy.types.Operator): if isinstance(hist, bmesh.types.BMFace) and hist.select: uvs = [l[uv_layer].uv.copy() for l in hist.loops] pin_uvs = [l[uv_layer].pin_uv for l in hist.loops] - seams = [l.edge.seam for l in hist.loops] + seams = [l.edge.seam for l in hist.loops] props.src_uvs.append(uvs) props.src_pin_uvs.append(pin_uvs) props.src_seams.append(seams) - if len(props.src_uvs) == 0 or len(props.src_pin_uvs) == 0: + if not props.src_uvs or not props.src_pin_uvs: self.report({'WARNING'}, "No faces are selected") return {'CANCELLED'} self.report({'INFO'}, "%d face(s) are selected" % len(props.src_uvs)) @@ -152,7 +152,7 @@ class MUV_CPUVSelSeqPasteUV(bpy.types.Operator): def execute(self, context): props = context.scene.muv_props.cpuv_selseq - if len(props.src_uvs) == 0 or len(props.src_pin_uvs) == 0: + if not props.src_uvs or not props.src_pin_uvs: self.report({'WARNING'}, "Need copy UV at first") return {'CANCELLED'} if self.uv_map == "": @@ -192,7 +192,7 @@ class MUV_CPUVSelSeqPasteUV(bpy.types.Operator): dest_uvs.append(uvs) dest_pin_uvs.append(pin_uvs) dest_seams.append(seams) - if len(dest_uvs) == 0 or len(dest_pin_uvs) == 0: + if not dest_uvs or not dest_pin_uvs: self.report({'WARNING'}, "No faces are selected") return {'CANCELLED'} if self.strategy == 'N_N' and len(props.src_uvs) != len(dest_uvs): @@ -239,7 +239,8 @@ class MUV_CPUVSelSeqPasteUV(bpy.types.Operator): spuvs_fr.insert(0, pin_uv) ss_fr.insert(0, s) # paste UVs - for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr, spuvs_fr, ss_fr): + for l, suv, spuv, ss in zip(bm.faces[idx].loops, suvs_fr, + spuvs_fr, ss_fr): l[uv_layer].uv = suv l[uv_layer].pin_uv = spuv if self.copy_seams is True: diff --git a/uv_magic_uv/muv_fliprot_ops.py b/uv_magic_uv/muv_fliprot_ops.py index 7b8b6a7f..334eb14c 100644 --- a/uv_magic_uv/muv_fliprot_ops.py +++ b/uv_magic_uv/muv_fliprot_ops.py @@ -20,15 +20,15 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy import bmesh from bpy.props import ( - BoolProperty, - IntProperty, - ) + BoolProperty, + IntProperty, +) from . import muv_common @@ -86,13 +86,14 @@ class MUV_FlipRot(bpy.types.Operator): dest_uvs.append(uvs) dest_pin_uvs.append(pin_uvs) dest_seams.append(seams) - if len(dest_uvs) == 0 or len(dest_pin_uvs) == 0: + if not dest_uvs or not dest_pin_uvs: self.report({'WARNING'}, "No faces are selected") return {'CANCELLED'} self.report({'INFO'}, "%d face(s) are selected" % len(dest_uvs)) # paste - for idx, duvs, dpuvs, dss in zip(dest_face_indices, dest_uvs, dest_pin_uvs, dest_seams): + for idx, duvs, dpuvs, dss in zip(dest_face_indices, dest_uvs, + dest_pin_uvs, dest_seams): duvs_fr = [uv for uv in duvs] dpuvs_fr = [pin_uv for pin_uv in dpuvs] dss_fr = [s for s in dss] diff --git a/uv_magic_uv/muv_menu.py b/uv_magic_uv/muv_menu.py index f53a8d7f..47c79bbd 100644 --- a/uv_magic_uv/muv_menu.py +++ b/uv_magic_uv/muv_menu.py @@ -20,8 +20,8 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy from . import muv_cpuv_ops @@ -29,6 +29,7 @@ from . import muv_cpuv_selseq_ops from . import muv_transuv_ops from . import muv_texlock_ops from . import muv_wsuv_ops +from . import muv_uvw_ops class MUV_CPUVMenu(bpy.types.Menu): @@ -119,3 +120,19 @@ class MUV_WSUVMenu(bpy.types.Menu): muv_wsuv_ops.MUV_WSUVMeasure.bl_idname, icon="IMAGE_COL") self.layout.operator( muv_wsuv_ops.MUV_WSUVApply.bl_idname, icon="IMAGE_COL") + + +class MUV_UVWMenu(bpy.types.Menu): + """ + Menu class: Master menu of UVW + """ + + bl_idname = "uv.muv_uvw_menu" + bl_label = "UVW" + bl_description = "" + + def draw(self, _): + self.layout.operator( + muv_uvw_ops.MUV_UVWBoxMap.bl_idname, icon="IMAGE_COL") + self.layout.operator( + muv_uvw_ops.MUV_UVWBestPlanerMap.bl_idname, icon="IMAGE_COL") diff --git a/uv_magic_uv/muv_mirroruv_ops.py b/uv_magic_uv/muv_mirroruv_ops.py index e1955360..63eb9bd5 100644 --- a/uv_magic_uv/muv_mirroruv_ops.py +++ b/uv_magic_uv/muv_mirroruv_ops.py @@ -20,14 +20,14 @@ __author__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy from bpy.props import ( - EnumProperty, - FloatProperty, - ) + EnumProperty, + FloatProperty, +) import bmesh from mathutils import Vector from . import muv_common diff --git a/uv_magic_uv/muv_mvuv_ops.py b/uv_magic_uv/muv_mvuv_ops.py index 847b34fe..28346270 100644 --- a/uv_magic_uv/muv_mvuv_ops.py +++ b/uv_magic_uv/muv_mvuv_ops.py @@ -20,8 +20,8 @@ __author__ = "kgeogeo, mem, Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy import bmesh diff --git a/uv_magic_uv/muv_packuv_ops.py b/uv_magic_uv/muv_packuv_ops.py index 66d32766..f663e662 100644 --- a/uv_magic_uv/muv_packuv_ops.py +++ b/uv_magic_uv/muv_packuv_ops.py @@ -20,8 +20,8 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" from math import fabs from collections import defaultdict @@ -30,10 +30,10 @@ import bpy import bmesh import mathutils from bpy.props import ( - FloatProperty, - FloatVectorProperty, - BoolProperty, - ) + FloatProperty, + FloatVectorProperty, + BoolProperty, +) from mathutils import Vector from . import muv_common @@ -279,7 +279,7 @@ class MUV_PackUV(bpy.types.Operator): uv_island_lists = [] faces_left = set(self.__face_to_verts.keys()) - while len(faces_left) > 0: + while faces_left: current_island = [] face_idx = list(faces_left)[0] self.__parse_island(bm, face_idx, faces_left, current_island) diff --git a/uv_magic_uv/muv_preferences.py b/uv_magic_uv/muv_preferences.py index fe807d67..e14ce99b 100644 --- a/uv_magic_uv/muv_preferences.py +++ b/uv_magic_uv/muv_preferences.py @@ -20,14 +20,14 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" from bpy.props import ( - BoolProperty, - FloatProperty, - FloatVectorProperty, - ) + BoolProperty, + FloatProperty, + FloatVectorProperty, +) from bpy.types import AddonPreferences diff --git a/uv_magic_uv/muv_preserve_uv_aspect.py b/uv_magic_uv/muv_preserve_uv_aspect.py index 93f53307..68e75f74 100644 --- a/uv_magic_uv/muv_preserve_uv_aspect.py +++ b/uv_magic_uv/muv_preserve_uv_aspect.py @@ -20,12 +20,12 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy import bmesh -from bpy.props import StringProperty +from bpy.props import StringProperty, EnumProperty from mathutils import Vector from . import muv_common @@ -41,6 +41,23 @@ class MUV_PreserveUVAspect(bpy.types.Operator): bl_options = {'REGISTER', 'UNDO'} dest_img_name = StringProperty(options={'HIDDEN'}) + origin = EnumProperty( + name="Origin", + description="Aspect Origin", + items=[ + ('CENTER', 'Center', 'Center'), + ('LEFT_TOP', 'Left Top', 'Left Bottom'), + ('LEFT_CENTER', 'Left Center', 'Left Center'), + ('LEFT_BOTTOM', 'Left Bottom', 'Left Bottom'), + ('CENTER_TOP', 'Center Top', 'Center Top'), + ('CENTER_BOTTOM', 'Center Bottom', 'Center Bottom'), + ('RIGHT_TOP', 'Right Top', 'Right Top'), + ('RIGHT_CENTER', 'Right Center', 'Right Center'), + ('RIGHT_BOTTOM', 'Right Bottom', 'Right Bottom') + + ], + default="CENTER" + ) @classmethod def poll(cls, context): @@ -83,12 +100,85 @@ class MUV_PreserveUVAspect(bpy.types.Operator): ratio = Vector(( dest_img.size[0] / src_img.size[0], dest_img.size[1] / src_img.size[1])) - origin = Vector((100000.0, 100000.0)) - for f in info[img]['faces']: - for l in f.loops: - uv = l[uv_layer].uv - origin.x = min(uv.x, origin.x) - origin.y = min(uv.y, origin.y) + + if self.origin == 'CENTER': + origin = Vector((0.0, 0.0)) + num = 0 + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin = origin + uv + num = num + 1 + origin = origin / num + elif self.origin == 'LEFT_TOP': + origin = Vector((100000.0, -100000.0)) + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = min(origin.x, uv.x) + origin.y = max(origin.y, uv.y) + elif self.origin == 'LEFT_CENTER': + origin = Vector((100000.0, 0.0)) + num = 0 + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = min(origin.x, uv.x) + origin.y = origin.y + uv.y + num = num + 1 + origin.y = origin.y / num + elif self.origin == 'LEFT_BOTTOM': + origin = Vector((100000.0, 100000.0)) + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = min(origin.x, uv.x) + origin.y = min(origin.y, uv.y) + elif self.origin == 'CENTER_TOP': + origin = Vector((0.0, -100000.0)) + num = 0 + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = origin.x + uv.x + origin.y = max(origin.y, uv.y) + num = num + 1 + origin.x = origin.x / num + elif self.origin == 'CENTER_BOTTOM': + origin = Vector((0.0, 100000.0)) + num = 0 + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = origin.x + uv.x + origin.y = min(origin.y, uv.y) + num = num + 1 + origin.x = origin.x / num + elif self.origin == 'RIGHT_TOP': + origin = Vector((-100000.0, -100000.0)) + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = max(origin.x, uv.x) + origin.y = max(origin.y, uv.y) + elif self.origin == 'RIGHT_CENTER': + origin = Vector((-100000.0, 0.0)) + num = 0 + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = max(origin.x, uv.x) + origin.y = origin.y + uv.y + num = num + 1 + origin.y = origin.y / num + elif self.origin == 'RIGHT_BOTTOM': + origin = Vector((-100000.0, 100000.0)) + for f in info[img]['faces']: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = max(origin.x, uv.x) + origin.y = min(origin.y, uv.y) + info[img]['ratio'] = ratio info[img]['origin'] = origin @@ -100,11 +190,14 @@ class MUV_PreserveUVAspect(bpy.types.Operator): f[tex_layer].image = dest_img for l in f.loops: uv = l[uv_layer].uv - diff = uv - info[img]['origin'] - diff.x = diff.x / info[img]['ratio'].x - diff.y = diff.y / info[img]['ratio'].y + origin = info[img]['origin'] + ratio = info[img]['ratio'] + diff = uv - origin + diff.x = diff.x / ratio.x + diff.y = diff.y / ratio.y uv.x = origin.x + diff.x uv.y = origin.y + diff.y + l[uv_layer].uv = uv bmesh.update_edit_mesh(obj.data) diff --git a/uv_magic_uv/muv_props.py b/uv_magic_uv/muv_props.py index 24f552d5..c0a7d961 100644 --- a/uv_magic_uv/muv_props.py +++ b/uv_magic_uv/muv_props.py @@ -20,15 +20,15 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy from bpy.props import ( - FloatProperty, - EnumProperty, - BoolProperty, - ) + FloatProperty, + EnumProperty, + BoolProperty, +) DEBUG = False diff --git a/uv_magic_uv/muv_texlock_ops.py b/uv_magic_uv/muv_texlock_ops.py index 08b42309..bfc95129 100644 --- a/uv_magic_uv/muv_texlock_ops.py +++ b/uv_magic_uv/muv_texlock_ops.py @@ -20,14 +20,14 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import math from math import ( - atan2, cos, - sqrt, sin, fabs, - ) + atan2, cos, + sqrt, sin, fabs, +) import bpy import bmesh diff --git a/uv_magic_uv/muv_texproj_ops.py b/uv_magic_uv/muv_texproj_ops.py index 1cf749ab..ffa4e789 100644 --- a/uv_magic_uv/muv_texproj_ops.py +++ b/uv_magic_uv/muv_texproj_ops.py @@ -20,8 +20,8 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" from collections import namedtuple diff --git a/uv_magic_uv/muv_transuv_ops.py b/uv_magic_uv/muv_transuv_ops.py index faf1304d..ed0a3c46 100644 --- a/uv_magic_uv/muv_transuv_ops.py +++ b/uv_magic_uv/muv_transuv_ops.py @@ -20,8 +20,8 @@ __author__ = "Nutti <nutti.metro@gmail.com>, Mifth, MaxRobinot" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" from collections import OrderedDict @@ -134,46 +134,48 @@ class MUV_TransUVPaste(bpy.types.Operator): # parse selection history for i, _ in enumerate(all_sel_faces): - if i > 0 and i % 2 != 0: - sel_faces = [all_sel_faces[i - 1], all_sel_faces[i]] - active_face = all_sel_faces[i] - - # parse all faces according to selection history - active_face_nor = active_face.normal.copy() - if self.invert_normals: - active_face_nor.negate() - all_sorted_faces = main_parse( - self, uv_layer, sel_faces, active_face, - active_face_nor) - - if all_sorted_faces: - # check amount of copied/pasted faces - if len(all_sorted_faces) != len(props.topology_copied): + if (i == 0) or (i % 2 == 0): + continue + sel_faces = [all_sel_faces[i - 1], all_sel_faces[i]] + active_face = all_sel_faces[i] + + # parse all faces according to selection history + active_face_nor = active_face.normal.copy() + if self.invert_normals: + active_face_nor.negate() + all_sorted_faces = main_parse( + self, uv_layer, sel_faces, active_face, + active_face_nor) + + if all_sorted_faces: + # check amount of copied/pasted faces + if len(all_sorted_faces) != len(props.topology_copied): + self.report( + {'WARNING'}, + "Mesh has different amount of faces" + ) + return {'FINISHED'} + + for j, face_data in enumerate(all_sorted_faces.values()): + copied_data = props.topology_copied[j] + + # check amount of copied/pasted verts + if len(copied_data[0]) != len(face_data[2]): + bpy.ops.mesh.select_all(action='DESELECT') + # select problematic face + list(all_sorted_faces.keys())[j].select = True self.report( {'WARNING'}, - "Mesh has different amount of faces" + "Face have different amount of vertices" ) return {'FINISHED'} - for i, face_data in enumerate(all_sorted_faces.values()): - copied_data = props.topology_copied[i] - - # check amount of copied/pasted verts - if len(copied_data[0]) != len(face_data[2]): - bpy.ops.mesh.select_all(action='DESELECT') - # select problematic face - list(all_sorted_faces.keys())[i].select = True - self.report( - {'WARNING'}, - "Face have different amount of vertices" - ) - return {'FINISHED'} - - for j, (edge, uvloop) in enumerate(zip(face_data[1], face_data[2])): - uvloop.uv = copied_data[0][j] - uvloop.pin_uv = copied_data[1][j] - if self.copy_seams: - edge.seam = copied_data[2][j] + for k, (edge, uvloop) in enumerate(zip(face_data[1], + face_data[2])): + uvloop.uv = copied_data[0][k] + uvloop.pin_uv = copied_data[1][k] + if self.copy_seams: + edge.seam = copied_data[2][k] bmesh.update_edit_mesh(active_obj.data) if self.copy_seams: diff --git a/uv_magic_uv/muv_unwrapconst_ops.py b/uv_magic_uv/muv_unwrapconst_ops.py index 28800c42..1a691119 100644 --- a/uv_magic_uv/muv_unwrapconst_ops.py +++ b/uv_magic_uv/muv_unwrapconst_ops.py @@ -18,16 +18,16 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy import bmesh from bpy.props import ( - BoolProperty, - EnumProperty, - FloatProperty, - ) + BoolProperty, + EnumProperty, + FloatProperty, +) from . import muv_common diff --git a/uv_magic_uv/muv_uvbb_ops.py b/uv_magic_uv/muv_uvbb_ops.py index c3fedf8e..4f7b0631 100644 --- a/uv_magic_uv/muv_uvbb_ops.py +++ b/uv_magic_uv/muv_uvbb_ops.py @@ -20,8 +20,8 @@ __author__ = "Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" from enum import IntEnum import math @@ -399,26 +399,25 @@ class MUV_UVBBStateNone(MUV_UVBBStateBase): prefs = context.user_preferences.addons["uv_magic_uv"].preferences cp_react_size = prefs.uvbb_cp_react_size is_uscaling = context.scene.muv_uvbb_uniform_scaling - if event.type == 'LEFTMOUSE': - if event.value == 'PRESS': - x, y = context.region.view2d.view_to_region( - mouse_view.x, mouse_view.y) - for i, p in enumerate(ctrl_points): - px, py = context.region.view2d.view_to_region(p.x, p.y) - in_cp_x = (px + cp_react_size > x and - px - cp_react_size < x) - in_cp_y = (py + cp_react_size > y and - py - cp_react_size < y) - if in_cp_x and in_cp_y: - if is_uscaling: - arr = [1, 3, 6, 8] - if i in arr: - return ( - MUV_UVBBState.UNIFORM_SCALING_1 + - arr.index(i) - ) - else: - return MUV_UVBBState.TRANSLATING + i + if (event.type == 'LEFTMOUSE') and (event.value == 'PRESS'): + x, y = context.region.view2d.view_to_region( + mouse_view.x, mouse_view.y) + for i, p in enumerate(ctrl_points): + px, py = context.region.view2d.view_to_region(p.x, p.y) + in_cp_x = (px + cp_react_size > x and + px - cp_react_size < x) + in_cp_y = (py + cp_react_size > y and + py - cp_react_size < y) + if in_cp_x and in_cp_y: + if is_uscaling: + arr = [1, 3, 6, 8] + if i in arr: + return ( + MUV_UVBBState.UNIFORM_SCALING_1 + + arr.index(i) + ) + else: + return MUV_UVBBState.TRANSLATING + i return MUV_UVBBState.NONE @@ -615,7 +614,7 @@ class MUV_UVBBUpdater(bpy.types.Operator): if f.select: for i, l in enumerate(f.loops): uv_info.append((f.index, i, l[uv_layer].uv.copy())) - if len(uv_info) == 0: + if not uv_info: return None return uv_info diff --git a/uv_magic_uv/muv_uvw_ops.py b/uv_magic_uv/muv_uvw_ops.py new file mode 100644 index 00000000..eb366e97 --- /dev/null +++ b/uv_magic_uv/muv_uvw_ops.py @@ -0,0 +1,222 @@ +# <pep8-80 compliant> + +# ##### BEGIN GPL LICENSE BLOCK ##### +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ##### END GPL LICENSE BLOCK ##### + +__author__ = "Alexander Milovsky, Nutti <nutti.metro@gmail.com>" +__status__ = "production" +__version__ = "4.5" +__date__ = "19 Nov 2017" + + +from math import sin, cos, pi + +import bpy +import bmesh +from bpy.props import ( + FloatProperty, + FloatVectorProperty +) +from mathutils import Vector + +from . import muv_common + + +class MUV_UVWBoxMap(bpy.types.Operator): + bl_idname = "uv.muv_uvw_box_map" + bl_label = "Box Map" + bl_options = {'REGISTER', 'UNDO'} + + size = FloatProperty( + name="Size", + default=1.0, + precision=4 + ) + rotation = FloatVectorProperty( + name="XYZ Rotation", + size=3, + default=(0.0, 0.0, 0.0) + ) + offset = FloatVectorProperty( + name="XYZ Offset", + size=3, + default=(0.0, 0.0, 0.0) + ) + tex_aspect = FloatProperty( + name="Texture Aspect", + default=1.0, + precision=4 + ) + + @classmethod + def poll(cls, context): + obj = context.active_object + return obj and obj.type == 'MESH' + + def execute(self, context): + obj = context.active_object + bm = bmesh.from_edit_mesh(obj.data) + if muv_common.check_version(2, 73, 0) >= 0: + bm.faces.ensure_lookup_table() + + # get UV layer + if not bm.loops.layers.uv: + self.report( + {'WARNING'}, "Object must have more than one UV map") + return {'CANCELLED'} + + uv_layer = bm.loops.layers.uv.verify() + + scale = 1.0 / self.size + + sx = 1.0 * scale + sy = 1.0 * scale + sz = 1.0 * scale + ofx = self.offset[0] + ofy = self.offset[1] + ofz = self.offset[2] + rx = self.rotation[0] * pi / 180.0 + ry = self.rotation[1] * pi / 180.0 + rz = self.rotation[2] * pi / 180.0 + aspect = self.tex_aspect + + sel_faces = [f for f in bm.faces if f.select] + + # update UV coordinate + for f in sel_faces: + n = f.normal + for l in f.loops: + co = l.vert.co + x = co.x * sx + y = co.y * sy + z = co.z * sz + + # X-plane + if abs(n[0]) >= abs(n[1]) and abs(n[0]) >= abs(n[2]): + if n[0] >= 0.0: + u = (y - ofy) * cos(rx) + (z - ofz) * sin(rx) + v = -(y * aspect - ofy) * sin(rx) +\ + (z * aspect - ofz) * cos(rx) + else: + u = -(y - ofy) * cos(rx) + (z - ofz) * sin(rx) + v = (y * aspect - ofy) * sin(rx) +\ + (z * aspect - ofz) * cos(rx) + # Y-plane + elif abs(n[1]) >= abs(n[0]) and abs(n[1]) >= abs(n[2]): + if n[1] >= 0.0: + u = -(x - ofx) * cos(ry) + (z - ofz) * sin(ry) + v = (x * aspect - ofx) * sin(ry) +\ + (z * aspect - ofz) * cos(ry) + else: + u = (x - ofx) * cos(ry) + (z - ofz) * sin(ry) + v = -(x * aspect - ofx) * sin(ry) +\ + (z * aspect - ofz) * cos(ry) + # Z-plane + else: + if n[2] >= 0.0: + u = (x - ofx) * cos(rz) + (y - ofy) * sin(rz) + v = -(x * aspect - ofx) * sin(rz) +\ + (y * aspect - ofy) * cos(rz) + else: + u = -(x - ofx) * cos(rz) - (y + ofy) * sin(rz) + v = -(x * aspect + ofx) * sin(rz) +\ + (y * aspect - ofy) * cos(rz) + + l[uv_layer].uv = Vector((u, v)) + + bmesh.update_edit_mesh(obj.data) + + return {'FINISHED'} + + +class MUV_UVWBestPlanerMap(bpy.types.Operator): + bl_idname = "uv.muv_uvw_best_planer_map" + bl_label = "Best Planer Map" + bl_options = {'REGISTER', 'UNDO'} + + size = FloatProperty( + name="Size", + default=1.0, + precision=4 + ) + rotation = FloatProperty( + name="XY Rotation", + default=0.0 + ) + offset = FloatVectorProperty( + name="XY Offset", + size=2, + default=(0.0, 0.0) + ) + tex_aspect = FloatProperty( + name="Texture Aspect", + default=1.0, + precision=4 + ) + + @classmethod + def poll(cls, context): + obj = context.active_object + return obj and obj.type == 'MESH' + + def execute(self, context): + obj = context.active_object + bm = bmesh.from_edit_mesh(obj.data) + if muv_common.check_version(2, 73, 0) >= 0: + bm.faces.ensure_lookup_table() + + # get UV layer + if not bm.loops.layers.uv: + self.report( + {'WARNING'}, "Object must have more than one UV map") + return {'CANCELLED'} + + uv_layer = bm.loops.layers.uv.verify() + + scale = 1.0 / self.size + + sx = 1.0 * scale + sy = 1.0 * scale + ofx = self.offset[0] + ofy = self.offset[1] + rz = self.rotation * pi / 180.0 + aspect = self.tex_aspect + + sel_faces = [f for f in bm.faces if f.select] + + # calculate average of normal + n_ave = Vector((0.0, 0.0, 0.0)) + for f in sel_faces: + n_ave = n_ave + f.normal + q = n_ave.rotation_difference(Vector((0.0, 0.0, 1.0))) + + # update UV coordinate + for f in sel_faces: + for l in f.loops: + co = q * l.vert.co + x = co.x * sx + y = co.y * sy + + u = x * cos(rz) - y * sin(rz) + ofx + v = -x * aspect * sin(rz) - y * aspect * cos(rz) + ofy + + l[uv_layer].uv = Vector((u, v)) + + bmesh.update_edit_mesh(obj.data) + + return {'FINISHED'} diff --git a/uv_magic_uv/muv_wsuv_ops.py b/uv_magic_uv/muv_wsuv_ops.py index 3e47d960..4ee8b4f9 100644 --- a/uv_magic_uv/muv_wsuv_ops.py +++ b/uv_magic_uv/muv_wsuv_ops.py @@ -20,12 +20,18 @@ __author__ = "McBuff, Nutti <nutti.metro@gmail.com>" __status__ = "production" -__version__ = "4.4" -__date__ = "2 Aug 2017" +__version__ = "4.5" +__date__ = "19 Nov 2017" import bpy import bmesh +from mathutils import Vector +from bpy.props import ( + FloatProperty, + BoolProperty, + EnumProperty +) from . import muv_common @@ -86,6 +92,9 @@ class MUV_WSUVMeasure(bpy.types.Operator): props.ref_scale = scale / len(sel_faces) + self.report( + {'INFO'}, "Average face size: {0}".format(props.ref_scale)) + return {'FINISHED'} @@ -99,6 +108,44 @@ class MUV_WSUVApply(bpy.types.Operator): bl_description = "Apply scaled UV based on scale calculation" bl_options = {'REGISTER', 'UNDO'} + proportional_scaling = BoolProperty( + name="Proportional Scaling", + default=True + ) + scaling_factor = FloatProperty( + name="Scaling Factor", + default=1.0, + max=1000.0, + min=0.00001 + ) + origin = EnumProperty( + name="Origin", + description="Aspect Origin", + items=[ + ('CENTER', 'Center', 'Center'), + ('LEFT_TOP', 'Left Top', 'Left Bottom'), + ('LEFT_CENTER', 'Left Center', 'Left Center'), + ('LEFT_BOTTOM', 'Left Bottom', 'Left Bottom'), + ('CENTER_TOP', 'Center Top', 'Center Top'), + ('CENTER_BOTTOM', 'Center Bottom', 'Center Bottom'), + ('RIGHT_TOP', 'Right Top', 'Right Top'), + ('RIGHT_CENTER', 'Right Center', 'Right Center'), + ('RIGHT_BOTTOM', 'Right Bottom', 'Right Bottom') + + ], + default="CENTER" + ) + + def draw(self, _): + layout = self.layout + + row = layout.row() + row.prop(self, "proportional_scaling") + row = layout.row() + row.prop(self, "scaling_factor") + if self.proportional_scaling: + row.enabled = False + def execute(self, context): props = context.scene.muv_props.wsuv obj = bpy.context.active_object @@ -122,26 +169,102 @@ class MUV_WSUVApply(bpy.types.Operator): scale = scale + calc_face_scale(uv_layer, f) scale = scale / len(sel_faces) - ratio = props.ref_scale / scale - - orig_area = bpy.context.area.type - bpy.context.area.type = 'IMAGE_EDITOR' - - # select all UV related to the selected faces - bpy.ops.uv.select_all(action='SELECT') - - # apply scaled UV - bpy.ops.transform.resize( - value=(ratio, ratio, ratio), - constraint_axis=(False, False, False), - constraint_orientation='GLOBAL', - mirror=False, - proportional='DISABLED', - proportional_edit_falloff='SMOOTH', - proportional_size=1) - - bpy.context.area.type = orig_area + self.report( + {'INFO'}, "Average face size: {0}".format(scale)) + + if self.proportional_scaling: + factor = props.ref_scale / scale + else: + factor = self.scaling_factor + + # calculate origin + if self.origin == 'CENTER': + origin = Vector((0.0, 0.0)) + num = 0 + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin = origin + uv + num = num + 1 + origin = origin / num + elif self.origin == 'LEFT_TOP': + origin = Vector((100000.0, -100000.0)) + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = min(origin.x, uv.x) + origin.y = max(origin.y, uv.y) + elif self.origin == 'LEFT_CENTER': + origin = Vector((100000.0, 0.0)) + num = 0 + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = min(origin.x, uv.x) + origin.y = origin.y + uv.y + num = num + 1 + origin.y = origin.y / num + elif self.origin == 'LEFT_BOTTOM': + origin = Vector((100000.0, 100000.0)) + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = min(origin.x, uv.x) + origin.y = min(origin.y, uv.y) + elif self.origin == 'CENTER_TOP': + origin = Vector((0.0, -100000.0)) + num = 0 + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = origin.x + uv.x + origin.y = max(origin.y, uv.y) + num = num + 1 + origin.x = origin.x / num + elif self.origin == 'CENTER_BOTTOM': + origin = Vector((0.0, 100000.0)) + num = 0 + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = origin.x + uv.x + origin.y = min(origin.y, uv.y) + num = num + 1 + origin.x = origin.x / num + elif self.origin == 'RIGHT_TOP': + origin = Vector((-100000.0, -100000.0)) + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = max(origin.x, uv.x) + origin.y = max(origin.y, uv.y) + elif self.origin == 'RIGHT_CENTER': + origin = Vector((-100000.0, 0.0)) + num = 0 + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = max(origin.x, uv.x) + origin.y = origin.y + uv.y + num = num + 1 + origin.y = origin.y / num + elif self.origin == 'RIGHT_BOTTOM': + origin = Vector((-100000.0, 100000.0)) + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + origin.x = max(origin.x, uv.x) + origin.y = min(origin.y, uv.y) + + # update UV coordinate + for f in sel_faces: + for l in f.loops: + uv = l[uv_layer].uv + diff = uv - origin + l[uv_layer].uv = origin + diff * factor bmesh.update_edit_mesh(obj.data) + self.report({'INFO'}, "Scaling factor: {0}".format(factor)) + return {'FINISHED'} |