Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornutti <nutti.metro@gmail.com>2019-01-15 08:56:07 +0300
committernutti <nutti.metro@gmail.com>2019-01-15 08:56:07 +0300
commit4fd7be071b037562c23cf4711abd54dffb667fdf (patch)
tree1126cadc9e97cbb9a2c6c437bb621e7bc6c2c00a /uv_magic_uv
parentd3ab0ed74a2532faec5cc87dbd2b93d59fbbdae0 (diff)
Magic UV: Fix error raised at UserPreferences and remove legacy codes.
Diffstat (limited to 'uv_magic_uv')
-rw-r--r--uv_magic_uv/__init__.py72
-rw-r--r--uv_magic_uv/common.py161
-rw-r--r--uv_magic_uv/impl/__init__.py70
-rw-r--r--uv_magic_uv/impl/align_uv_cursor_impl.py239
-rw-r--r--uv_magic_uv/impl/align_uv_impl.py820
-rw-r--r--uv_magic_uv/impl/copy_paste_uv_impl.py271
-rw-r--r--uv_magic_uv/impl/copy_paste_uv_uvedit_impl.py166
-rw-r--r--uv_magic_uv/impl/flip_rotate_impl.py133
-rw-r--r--uv_magic_uv/impl/mirror_uv_impl.py158
-rw-r--r--uv_magic_uv/impl/move_uv_impl.py166
-rw-r--r--uv_magic_uv/impl/pack_uv_impl.py202
-rw-r--r--uv_magic_uv/impl/preserve_uv_aspect_impl.py359
-rw-r--r--uv_magic_uv/impl/select_uv_impl.py120
-rw-r--r--uv_magic_uv/impl/smooth_uv_impl.py215
-rw-r--r--uv_magic_uv/impl/texture_lock_impl.py455
-rw-r--r--uv_magic_uv/impl/texture_projection_impl.py126
-rw-r--r--uv_magic_uv/impl/texture_wrap_impl.py236
-rw-r--r--uv_magic_uv/impl/transfer_uv_impl.py330
-rw-r--r--uv_magic_uv/impl/unwrap_constraint_impl.py98
-rw-r--r--uv_magic_uv/impl/uv_bounding_box_impl.py55
-rw-r--r--uv_magic_uv/impl/uv_inspection_impl.py70
-rw-r--r--uv_magic_uv/impl/uv_sculpt_impl.py57
-rw-r--r--uv_magic_uv/impl/uvw_impl.py160
-rw-r--r--uv_magic_uv/impl/world_scale_uv_impl.py383
-rw-r--r--uv_magic_uv/legacy/__init__.py38
-rw-r--r--uv_magic_uv/legacy/op/__init__.py74
-rw-r--r--uv_magic_uv/legacy/op/align_uv.py231
-rw-r--r--uv_magic_uv/legacy/op/align_uv_cursor.py153
-rw-r--r--uv_magic_uv/legacy/op/copy_paste_uv.py531
-rw-r--r--uv_magic_uv/legacy/op/copy_paste_uv_object.py298
-rw-r--r--uv_magic_uv/legacy/op/copy_paste_uv_uvedit.py97
-rw-r--r--uv_magic_uv/legacy/op/flip_rotate_uv.py132
-rw-r--r--uv_magic_uv/legacy/op/mirror_uv.py110
-rw-r--r--uv_magic_uv/legacy/op/move_uv.py82
-rw-r--r--uv_magic_uv/legacy/op/pack_uv.py129
-rw-r--r--uv_magic_uv/legacy/op/preserve_uv_aspect.py124
-rw-r--r--uv_magic_uv/legacy/op/select_uv.py92
-rw-r--r--uv_magic_uv/legacy/op/smooth_uv.py105
-rw-r--r--uv_magic_uv/legacy/op/texture_lock.py158
-rw-r--r--uv_magic_uv/legacy/op/texture_projection.py296
-rw-r--r--uv_magic_uv/legacy/op/texture_wrap.py113
-rw-r--r--uv_magic_uv/legacy/op/transfer_uv.py172
-rw-r--r--uv_magic_uv/legacy/op/unwrap_constraint.py125
-rw-r--r--uv_magic_uv/legacy/op/uv_bounding_box.py810
-rw-r--r--uv_magic_uv/legacy/op/uv_inspection.py231
-rw-r--r--uv_magic_uv/legacy/op/uv_sculpt.py450
-rw-r--r--uv_magic_uv/legacy/op/uvw.py181
-rw-r--r--uv_magic_uv/legacy/op/world_scale_uv.py359
-rw-r--r--uv_magic_uv/legacy/preferences.py518
-rw-r--r--uv_magic_uv/legacy/properites.py61
-rw-r--r--uv_magic_uv/legacy/ui/IMAGE_MT_uvs.py197
-rw-r--r--uv_magic_uv/legacy/ui/VIEW3D_MT_object.py54
-rw-r--r--uv_magic_uv/legacy/ui/VIEW3D_MT_uv_map.py257
-rw-r--r--uv_magic_uv/legacy/ui/__init__.py50
-rw-r--r--uv_magic_uv/legacy/ui/uvedit_copy_paste_uv.py62
-rw-r--r--uv_magic_uv/legacy/ui/uvedit_editor_enhancement.py149
-rw-r--r--uv_magic_uv/legacy/ui/uvedit_uv_manipulation.py130
-rw-r--r--uv_magic_uv/legacy/ui/view3d_copy_paste_uv_editmode.py93
-rw-r--r--uv_magic_uv/legacy/ui/view3d_copy_paste_uv_objectmode.py65
-rw-r--r--uv_magic_uv/legacy/ui/view3d_uv_manipulation.py289
-rw-r--r--uv_magic_uv/legacy/ui/view3d_uv_mapping.py116
-rw-r--r--uv_magic_uv/lib/bglx.py77
-rw-r--r--uv_magic_uv/op/align_uv.py818
-rw-r--r--uv_magic_uv/op/align_uv_cursor.py156
-rw-r--r--uv_magic_uv/op/copy_paste_uv.py337
-rw-r--r--uv_magic_uv/op/copy_paste_uv_object.py67
-rw-r--r--uv_magic_uv/op/copy_paste_uv_uvedit.py136
-rw-r--r--uv_magic_uv/op/flip_rotate_uv.py132
-rw-r--r--uv_magic_uv/op/mirror_uv.py131
-rw-r--r--uv_magic_uv/op/move_uv.py125
-rw-r--r--uv_magic_uv/op/pack_uv.py183
-rw-r--r--uv_magic_uv/op/preserve_uv_aspect.py197
-rw-r--r--uv_magic_uv/op/select_uv.py91
-rw-r--r--uv_magic_uv/op/smooth_uv.py196
-rw-r--r--uv_magic_uv/op/texture_lock.py421
-rw-r--r--uv_magic_uv/op/texture_projection.py175
-rw-r--r--uv_magic_uv/op/texture_wrap.py203
-rw-r--r--uv_magic_uv/op/transfer_uv.py329
-rw-r--r--uv_magic_uv/op/unwrap_constraint.py87
-rw-r--r--uv_magic_uv/op/uv_bounding_box.py83
-rw-r--r--uv_magic_uv/op/uv_inspection.py93
-rw-r--r--uv_magic_uv/op/uv_sculpt.py76
-rw-r--r--uv_magic_uv/op/uvw.py177
-rw-r--r--uv_magic_uv/op/world_scale_uv.py384
-rw-r--r--uv_magic_uv/preferences.py95
-rw-r--r--uv_magic_uv/properites.py11
-rw-r--r--uv_magic_uv/ui/IMAGE_MT_uvs.py4
-rw-r--r--uv_magic_uv/ui/VIEW3D_MT_object.py4
-rw-r--r--uv_magic_uv/ui/VIEW3D_MT_uv_map.py11
-rw-r--r--uv_magic_uv/ui/uvedit_copy_paste_uv.py8
-rw-r--r--uv_magic_uv/ui/uvedit_editor_enhancement.py8
-rw-r--r--uv_magic_uv/ui/uvedit_uv_manipulation.py4
-rw-r--r--uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py8
-rw-r--r--uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py8
-rw-r--r--uv_magic_uv/ui/view3d_uv_manipulation.py36
-rw-r--r--uv_magic_uv/ui/view3d_uv_mapping.py8
-rw-r--r--uv_magic_uv/utils/__init__.py2
-rw-r--r--uv_magic_uv/utils/bl_class_registry.py4
-rw-r--r--uv_magic_uv/utils/compatibility.py189
-rw-r--r--uv_magic_uv/utils/property_class_registry.py4
100 files changed, 4506 insertions, 12826 deletions
diff --git a/uv_magic_uv/__init__.py b/uv_magic_uv/__init__.py
index 61fcc804..ae0317ed 100644
--- a/uv_magic_uv/__init__.py
+++ b/uv_magic_uv/__init__.py
@@ -41,47 +41,24 @@ bl_info = {
"category": "UV"
}
-def check_version(major, minor, _):
- """
- Check blender version
- """
-
- if bpy.app.version[0] == major and bpy.app.version[1] == minor:
- return 0
- if bpy.app.version[0] > major:
- return 1
- if bpy.app.version[1] > minor:
- return 1
- return -1
-
if "bpy" in locals():
import importlib
importlib.reload(common)
importlib.reload(utils)
utils.bl_class_registry.BlClassRegistry.cleanup()
- if check_version(2, 80, 0) >= 0:
- importlib.reload(lib)
- importlib.reload(op)
- importlib.reload(ui)
- importlib.reload(properites)
- importlib.reload(preferences)
- else:
- importlib.reload(legacy)
- importlib.reload(impl)
+ importlib.reload(op)
+ importlib.reload(ui)
+ importlib.reload(properites)
+ importlib.reload(preferences)
else:
import bpy
from . import common
from . import utils
- if check_version(2, 80, 0) >= 0:
- from . import lib
- from . import op
- from . import ui
- from . import properites
- from . import preferences
- else:
- from . import legacy
- from . import impl
+ from . import op
+ from . import ui
+ from . import properites
+ from . import preferences
import os
@@ -95,9 +72,8 @@ def register_updater(bl_info):
config.current_addon_path = os.path.dirname(os.path.realpath(__file__))
config.branches = ["master", "develop"]
config.addon_directory = config.current_addon_path[:config.current_addon_path.rfind("/")]
- #config.min_release_version = bl_info["version"]
- config.min_release_version = (5, 1)
- config.target_addon_path = "uv_magic_uv"
+ config.min_release_version = bl_info["version"]
+ config.target_addon_path = "src/uv_magic_uv"
updater = utils.addon_updator.AddonUpdatorManager.get_instance()
updater.init(bl_info, config)
@@ -105,29 +81,17 @@ def register_updater(bl_info):
def register():
register_updater(bl_info)
- if common.check_version(2, 80, 0) >= 0:
- utils.bl_class_registry.BlClassRegistry.register()
- properites.init_props(bpy.types.Scene)
- if bpy.context.user_preferences.addons['uv_magic_uv'].preferences.enable_builtin_menu:
- preferences.add_builtin_menu()
- else:
- utils.bl_class_registry.BlClassRegistry.register()
- legacy.properites.init_props(bpy.types.Scene)
- if legacy.preferences.Preferences.enable_builtin_menu:
- legacy.preferences.add_builtin_menu()
+ utils.bl_class_registry.BlClassRegistry.register()
+ properites.init_props(bpy.types.Scene)
+ if utils.compatibility.get_user_preferences(bpy.context).addons['uv_magic_uv'].preferences.enable_builtin_menu:
+ preferences.add_builtin_menu()
def unregister():
- if common.check_version(2, 80, 0) >= 0:
- if bpy.context.user_preferences.addons['uv_magic_uv'].preferences.enable_builtin_menu:
- preferences.remove_builtin_menu()
- properites.clear_props(bpy.types.Scene)
- utils.bl_class_registry.BlClassRegistry.unregister()
- else:
- if legacy.preferences.Preferences.enable_builtin_menu:
- legacy.preferences.remove_builtin_menu()
- legacy.properites.clear_props(bpy.types.Scene)
- utils.bl_class_registry.BlClassRegistry.unregister()
+ if utils.compatibility.get_user_preferences(bpy.context).addons['uv_magic_uv'].preferences.enable_builtin_menu:
+ preferences.remove_builtin_menu()
+ properites.clear_props(bpy.types.Scene)
+ utils.bl_class_registry.BlClassRegistry.unregister()
if __name__ == "__main__":
diff --git a/uv_magic_uv/common.py b/uv_magic_uv/common.py
index 83c6ae74..961ce447 100644
--- a/uv_magic_uv/common.py
+++ b/uv_magic_uv/common.py
@@ -32,37 +32,10 @@ import bpy
from mathutils import Vector
import bmesh
+from .utils import compatibility as compat
-__all__ = [
- 'is_console_mode',
- 'is_debug_mode',
- 'enable_debugg_mode',
- 'disable_debug_mode',
- 'debug_print',
- 'check_version',
- 'redraw_all_areas',
- 'get_space_legacy',
- 'mouse_on_region_legacy',
- 'mouse_on_area_legacy',
- 'mouse_on_regions_legacy',
- 'create_bmesh',
- 'create_new_uv_map',
- 'get_island_info',
- 'get_island_info_from_bmesh',
- 'get_island_info_from_faces',
- 'get_uvimg_editor_board_size',
- 'calc_polygon_2d_area',
- 'calc_polygon_3d_area',
- 'measure_mesh_area',
- 'measure_uv_area_legacy',
- 'diff_point_to_segment',
- 'get_loop_sequences',
- 'get_overlapped_uv_info',
- 'get_flipped_uv_info',
-]
-
-
-__DEBUG_MODE = True
+
+__DEBUG_MODE = False
def is_console_mode():
@@ -119,70 +92,6 @@ def redraw_all_areas():
area.tag_redraw()
-def get_space_legacy(area_type, region_type, space_type):
- """
- Get current area/region/space
- """
-
- area = None
- region = None
- space = None
-
- for area in bpy.context.screen.areas:
- if area.type == area_type:
- break
- else:
- return (None, None, None)
- for region in area.regions:
- if region.type == region_type:
- break
- for space in area.spaces:
- if space.type == space_type:
- break
-
- return (area, region, space)
-
-
-def mouse_on_region_legacy(event, area_type, region_type):
- pos = Vector((event.mouse_x, event.mouse_y))
-
- _, region, _ = get_space_legacy(area_type, region_type, "")
- if region is None:
- return False
-
- if (pos.x > region.x) and (pos.x < region.x + region.width) and \
- (pos.y > region.y) and (pos.y < region.y + region.height):
- return True
-
- return False
-
-
-def mouse_on_area_legacy(event, area_type):
- pos = Vector((event.mouse_x, event.mouse_y))
-
- area, _, _ = get_space_legacy(area_type, "", "")
- if area is None:
- return False
-
- if (pos.x > area.x) and (pos.x < area.x + area.width) and \
- (pos.y > area.y) and (pos.y < area.y + area.height):
- return True
-
- return False
-
-
-def mouse_on_regions_legacy(event, area_type, regions):
- if not mouse_on_area_legacy(event, area_type):
- return False
-
- for region in regions:
- result = mouse_on_region_legacy(event, area_type, region)
- if result:
- return True
-
- return False
-
-
def get_space(area_type, region_type, space_type):
"""
Get current area/region/space
@@ -199,8 +108,9 @@ def get_space(area_type, region_type, space_type):
return (None, None, None)
for region in area.regions:
if region.type == region_type:
- if region.width <= 1 or region.height <= 1:
- continue
+ if compat.check_version(2, 80, 0) >= 0:
+ if region.width <= 1 or region.height <= 1:
+ continue
break
else:
return (area, None, None)
@@ -460,65 +370,6 @@ def measure_mesh_area(obj):
return mesh_area
-def measure_uv_area_legacy(obj, tex_size=None):
- bm = bmesh.from_edit_mesh(obj.data)
- if check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- if not bm.faces.layers.tex:
- return None
- tex_layer = bm.faces.layers.tex.verify()
-
- sel_faces = [f for f in bm.faces if f.select]
-
- # measure
- uv_area = 0.0
- for f in sel_faces:
- uvs = [l[uv_layer].uv for l in f.loops]
- f_uv_area = calc_polygon_2d_area(uvs)
-
- # user specified
- if tex_size:
- uv_area = uv_area + f_uv_area * tex_size[0] * tex_size[1]
- continue
-
- # try to find from texture_layer
- img = None
- if tex_layer:
- img = f[tex_layer].image
-
- # not found, then try to search from node
- if not img:
- for mat in obj.material_slots:
- if not mat.material.node_tree:
- continue
- for node in mat.material.node_tree.nodes:
- tex_node_types = [
- 'TEX_ENVIRONMENT',
- 'TEX_IMAGE',
- ]
- if node.type not in tex_node_types:
- continue
- if not node.image:
- continue
- img = node.image
-
- # can not find from node, so we can not get texture size
- if not img:
- return None
-
- img_size = img.size
- uv_area = uv_area + f_uv_area * img_size[0] * img_size[1]
-
- return uv_area
-
-
def find_texture_layer(bm):
if check_version(2, 80, 0) >= 0:
return None
diff --git a/uv_magic_uv/impl/__init__.py b/uv_magic_uv/impl/__init__.py
deleted file mode 100644
index d22125af..00000000
--- a/uv_magic_uv/impl/__init__.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
- import importlib
- importlib.reload(align_uv_cursor_impl)
- importlib.reload(align_uv_impl)
- importlib.reload(copy_paste_uv_impl)
- importlib.reload(copy_paste_uv_uvedit_impl)
- importlib.reload(flip_rotate_impl)
- importlib.reload(mirror_uv_impl)
- importlib.reload(move_uv_impl)
- importlib.reload(pack_uv_impl)
- importlib.reload(preserve_uv_aspect_impl)
- importlib.reload(select_uv_impl)
- importlib.reload(smooth_uv_impl)
- importlib.reload(texture_lock_impl)
- importlib.reload(texture_wrap_impl)
- importlib.reload(transfer_uv_impl)
- importlib.reload(unwrap_constraint_impl)
- importlib.reload(uv_bounding_box_impl)
- importlib.reload(uv_inspection_impl)
- importlib.reload(uv_sculpt_impl)
- importlib.reload(uvw_impl)
- importlib.reload(world_scale_uv_impl)
-else:
- from . import align_uv_cursor_impl
- from . import align_uv_impl
- from . import copy_paste_uv_impl
- from . import copy_paste_uv_uvedit_impl
- from . import flip_rotate_impl
- from . import mirror_uv_impl
- from . import move_uv_impl
- from . import pack_uv_impl
- from . import preserve_uv_aspect_impl
- from . import select_uv_impl
- from . import smooth_uv_impl
- from . import texture_lock_impl
- from . import texture_wrap_impl
- from . import transfer_uv_impl
- from . import unwrap_constraint_impl
- from . import uv_bounding_box_impl
- from . import uv_inspection_impl
- from . import uv_sculpt_impl
- from . import uvw_impl
- from . import world_scale_uv_impl
-
-import bpy
diff --git a/uv_magic_uv/impl/align_uv_cursor_impl.py b/uv_magic_uv/impl/align_uv_cursor_impl.py
deleted file mode 100644
index 3056e87b..00000000
--- a/uv_magic_uv/impl/align_uv_cursor_impl.py
+++ /dev/null
@@ -1,239 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from mathutils import Vector
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
-
-
-class AlignUVCursorLegacyImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, ops_obj, context):
- area, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
- 'IMAGE_EDITOR')
- bd_size = common.get_uvimg_editor_board_size(area)
-
- if ops_obj.base == 'UV':
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if not bm.loops.layers.uv:
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- max_ = Vector((-10000000.0, -10000000.0))
- min_ = Vector((10000000.0, 10000000.0))
- for f in bm.faces:
- if not f.select:
- continue
- for l in f.loops:
- uv = l[uv_layer].uv
- max_.x = max(max_.x, uv.x)
- max_.y = max(max_.y, uv.y)
- min_.x = min(min_.x, uv.x)
- min_.y = min(min_.y, uv.y)
- center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
- elif ops_obj.base == 'UV_SEL':
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if not bm.loops.layers.uv:
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- max_ = Vector((-10000000.0, -10000000.0))
- min_ = Vector((10000000.0, 10000000.0))
- for f in bm.faces:
- if not f.select:
- continue
- for l in f.loops:
- if not l[uv_layer].select:
- continue
- uv = l[uv_layer].uv
- max_.x = max(max_.x, uv.x)
- max_.y = max(max_.y, uv.y)
- min_.x = min(min_.x, uv.x)
- min_.y = min(min_.y, uv.y)
- center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
- elif ops_obj.base == 'TEXTURE':
- min_ = Vector((0.0, 0.0))
- max_ = Vector((1.0, 1.0))
- center = Vector((0.5, 0.5))
- else:
- ops_obj.report({'ERROR'}, "Unknown Operation")
- return {'CANCELLED'}
-
- if ops_obj.position == 'CENTER':
- cx = center.x * bd_size[0]
- cy = center.y * bd_size[1]
- elif ops_obj.position == 'LEFT_TOP':
- cx = min_.x * bd_size[0]
- cy = max_.y * bd_size[1]
- elif ops_obj.position == 'LEFT_MIDDLE':
- cx = min_.x * bd_size[0]
- cy = center.y * bd_size[1]
- elif ops_obj.position == 'LEFT_BOTTOM':
- cx = min_.x * bd_size[0]
- cy = min_.y * bd_size[1]
- elif ops_obj.position == 'MIDDLE_TOP':
- cx = center.x * bd_size[0]
- cy = max_.y * bd_size[1]
- elif ops_obj.position == 'MIDDLE_BOTTOM':
- cx = center.x * bd_size[0]
- cy = min_.y * bd_size[1]
- elif ops_obj.position == 'RIGHT_TOP':
- cx = max_.x * bd_size[0]
- cy = max_.y * bd_size[1]
- elif ops_obj.position == 'RIGHT_MIDDLE':
- cx = max_.x * bd_size[0]
- cy = center.y * bd_size[1]
- elif ops_obj.position == 'RIGHT_BOTTOM':
- cx = max_.x * bd_size[0]
- cy = min_.y * bd_size[1]
- else:
- ops_obj.report({'ERROR'}, "Unknown Operation")
- return {'CANCELLED'}
-
- space.cursor_location = Vector((cx, cy))
-
- return {'FINISHED'}
-
-
-class AlignUVCursorImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, ops_obj, context):
- _, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
- 'IMAGE_EDITOR')
-
- if ops_obj.base == 'UV':
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if not bm.loops.layers.uv:
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- max_ = Vector((-10000000.0, -10000000.0))
- min_ = Vector((10000000.0, 10000000.0))
- for f in bm.faces:
- if not f.select:
- continue
- for l in f.loops:
- uv = l[uv_layer].uv
- max_.x = max(max_.x, uv.x)
- max_.y = max(max_.y, uv.y)
- min_.x = min(min_.x, uv.x)
- min_.y = min(min_.y, uv.y)
- center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
- elif ops_obj.base == 'UV_SEL':
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if not bm.loops.layers.uv:
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- max_ = Vector((-10000000.0, -10000000.0))
- min_ = Vector((10000000.0, 10000000.0))
- for f in bm.faces:
- if not f.select:
- continue
- for l in f.loops:
- if not l[uv_layer].select:
- continue
- uv = l[uv_layer].uv
- max_.x = max(max_.x, uv.x)
- max_.y = max(max_.y, uv.y)
- min_.x = min(min_.x, uv.x)
- min_.y = min(min_.y, uv.y)
- center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
-
- elif ops_obj.base == 'TEXTURE':
- min_ = Vector((0.0, 0.0))
- max_ = Vector((1.0, 1.0))
- center = Vector((0.5, 0.5))
- else:
- ops_obj.report({'ERROR'}, "Unknown Operation")
- return {'CANCELLED'}
-
- if ops_obj.position == 'CENTER':
- cx = center.x
- cy = center.y
- elif ops_obj.position == 'LEFT_TOP':
- cx = min_.x
- cy = max_.y
- elif ops_obj.position == 'LEFT_MIDDLE':
- cx = min_.x
- cy = center.y
- elif ops_obj.position == 'LEFT_BOTTOM':
- cx = min_.x
- cy = min_.y
- elif ops_obj.position == 'MIDDLE_TOP':
- cx = center.x
- cy = max_.y
- elif ops_obj.position == 'MIDDLE_BOTTOM':
- cx = center.x
- cy = min_.y
- elif ops_obj.position == 'RIGHT_TOP':
- cx = max_.x
- cy = max_.y
- elif ops_obj.position == 'RIGHT_MIDDLE':
- cx = max_.x
- cy = center.y
- elif ops_obj.position == 'RIGHT_BOTTOM':
- cx = max_.x
- cy = min_.y
- else:
- ops_obj.report({'ERROR'}, "Unknown Operation")
- return {'CANCELLED'}
-
- space.cursor_location = Vector((cx, cy))
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/align_uv_impl.py b/uv_magic_uv/impl/align_uv_impl.py
deleted file mode 100644
index b8d7d33d..00000000
--- a/uv_magic_uv/impl/align_uv_impl.py
+++ /dev/null
@@ -1,820 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import math
-from math import atan2, tan, sin, cos
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-def _is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
-
-
-# get sum vertex length of loop sequences
-def _get_loop_vert_len(loops):
- length = 0
- for l1, l2 in zip(loops[:-1], loops[1:]):
- diff = l2.vert.co - l1.vert.co
- length = length + abs(diff.length)
-
- return length
-
-
-# get sum uv length of loop sequences
-def _get_loop_uv_len(loops, uv_layer):
- length = 0
- for l1, l2 in zip(loops[:-1], loops[1:]):
- diff = l2[uv_layer].uv - l1[uv_layer].uv
- length = length + abs(diff.length)
-
- return length
-
-
-# get center/radius of circle by 3 vertices
-def _get_circle(v):
- alpha = atan2((v[0].y - v[1].y), (v[0].x - v[1].x)) + math.pi / 2
- beta = atan2((v[1].y - v[2].y), (v[1].x - v[2].x)) + math.pi / 2
- ex = (v[0].x + v[1].x) / 2.0
- ey = (v[0].y + v[1].y) / 2.0
- fx = (v[1].x + v[2].x) / 2.0
- fy = (v[1].y + v[2].y) / 2.0
- cx = (ey - fy - ex * tan(alpha) + fx * tan(beta)) / \
- (tan(beta) - tan(alpha))
- cy = ey - (ex - cx) * tan(alpha)
- center = Vector((cx, cy))
-
- r = v[0] - center
- radian = r.length
-
- return center, radian
-
-
-# get position on circle with same arc length
-def _calc_v_on_circle(v, center, radius):
- base = v[0]
- theta = atan2(base.y - center.y, base.x - center.x)
- new_v = []
- for i in range(len(v)):
- angle = theta + i * 2 * math.pi / len(v)
- new_v.append(Vector((center.x + radius * sin(angle),
- center.y + radius * cos(angle))))
-
- return new_v
-
-
-class CircleImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- uv_layer = bm.loops.layers.uv.verify()
-
- # loop_seqs[horizontal][vertical][loop]
- loop_seqs, error = common.get_loop_sequences(bm, uv_layer, True)
- if not loop_seqs:
- ops_obj.report({'WARNING'}, error)
- return {'CANCELLED'}
-
- # get circle and new UVs
- uvs = [hseq[0][0][uv_layer].uv.copy() for hseq in loop_seqs]
- c, r = _get_circle(uvs[0:3])
- new_uvs = _calc_v_on_circle(uvs, c, r)
-
- # check center UV of circle
- center = loop_seqs[0][-1][0].vert
- for hseq in loop_seqs[1:]:
- if len(hseq[-1]) != 1:
- ops_obj.report({'WARNING'}, "Last face must be triangle")
- return {'CANCELLED'}
- if hseq[-1][0].vert != center:
- ops_obj.report({'WARNING'}, "Center must be identical")
- return {'CANCELLED'}
-
- # align to circle
- if ops_obj.transmission:
- for hidx, hseq in enumerate(loop_seqs):
- for vidx, pair in enumerate(hseq):
- all_ = int((len(hseq) + 1) / 2)
- r = (all_ - int((vidx + 1) / 2)) / all_
- pair[0][uv_layer].uv = c + (new_uvs[hidx] - c) * r
- if ops_obj.select:
- pair[0][uv_layer].select = True
-
- if len(pair) < 2:
- continue
- # for quad polygon
- next_hidx = (hidx + 1) % len(loop_seqs)
- pair[1][uv_layer].uv = c + ((new_uvs[next_hidx]) - c) * r
- if ops_obj.select:
- pair[1][uv_layer].select = True
- else:
- for hidx, hseq in enumerate(loop_seqs):
- pair = hseq[0]
- pair[0][uv_layer].uv = new_uvs[hidx]
- pair[1][uv_layer].uv = new_uvs[(hidx + 1) % len(loop_seqs)]
- if ops_obj.select:
- pair[0][uv_layer].select = True
- pair[1][uv_layer].select = True
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
-
-
-# get accumulate vertex lengths of loop sequences
-def _get_loop_vert_accum_len(loops):
- accum_lengths = [0.0]
- length = 0
- for l1, l2 in zip(loops[:-1], loops[1:]):
- diff = l2.vert.co - l1.vert.co
- length = length + abs(diff.length)
- accum_lengths.extend([length])
-
- return accum_lengths
-
-
-# get sum uv length of loop sequences
-def _get_loop_uv_accum_len(loops, uv_layer):
- accum_lengths = [0.0]
- length = 0
- for l1, l2 in zip(loops[:-1], loops[1:]):
- diff = l2[uv_layer].uv - l1[uv_layer].uv
- length = length + abs(diff.length)
- accum_lengths.extend([length])
-
- return accum_lengths
-
-
-# get horizontal differential of UV influenced by mesh vertex
-def _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
- common.debug_print(
- "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
-
- base_uv = loop_seqs[0][vidx][0][uv_layer].uv.copy()
-
- # calculate original length
- hloops = []
- for s in loop_seqs:
- hloops.extend([s[vidx][0], s[vidx][1]])
- total_vlen = _get_loop_vert_len(hloops)
- accum_vlens = _get_loop_vert_accum_len(hloops)
- total_uvlen = _get_loop_uv_len(hloops, uv_layer)
- accum_uvlens = _get_loop_uv_accum_len(hloops, uv_layer)
- orig_uvs = [l[uv_layer].uv.copy() for l in hloops]
-
- # calculate target length
- tgt_noinfl = total_uvlen * (hidx + pidx) / len(loop_seqs)
- tgt_infl = total_uvlen * accum_vlens[hidx * 2 + pidx] / total_vlen
- target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
- common.debug_print(target_length)
- common.debug_print(accum_uvlens)
-
- # calculate target UV
- for i in range(len(accum_uvlens[:-1])):
- # get line segment which UV will be placed
- if ((accum_uvlens[i] <= target_length) and
- (accum_uvlens[i + 1] > target_length)):
- tgt_seg_len = target_length - accum_uvlens[i]
- seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
- uv1 = orig_uvs[i]
- uv2 = orig_uvs[i + 1]
- target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
- break
- elif i == (len(accum_uvlens[:-1]) - 1):
- if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
- raise Exception(
- "Internal Error: horizontal_target_length={}"
- " is not equal to {}"
- .format(target_length, accum_uvlens[-1]))
- tgt_seg_len = target_length - accum_uvlens[i]
- seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
- uv1 = orig_uvs[i]
- uv2 = orig_uvs[i + 1]
- target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
- break
- else:
- raise Exception("Internal Error: horizontal_target_length={}"
- " is not in range {} to {}"
- .format(target_length, accum_uvlens[0],
- accum_uvlens[-1]))
-
- return target_uv
-
-
-# --------------------- LOOP STRUCTURE ----------------------
-#
-# loops[hidx][vidx][pidx]
-# hidx: horizontal index
-# vidx: vertical index
-# pidx: pair index
-#
-# <----- horizontal ----->
-#
-# (hidx, vidx, pidx) = (0, 3, 0)
-# | (hidx, vidx, pidx) = (1, 3, 0)
-# v v
-# ^ o --- oo --- o
-# | | || |
-# vertical | o --- oo --- o <- (hidx, vidx, pidx)
-# | o --- oo --- o = (1, 2, 1)
-# | | || |
-# v o --- oo --- o
-# ^ ^
-# | (hidx, vidx, pidx) = (1, 0, 1)
-# (hidx, vidx, pidx) = (0, 0, 0)
-#
-# -----------------------------------------------------------
-
-
-# get vertical differential of UV influenced by mesh vertex
-def _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
- common.debug_print(
- "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
-
- base_uv = loop_seqs[hidx][0][pidx][uv_layer].uv.copy()
-
- # calculate original length
- vloops = []
- for s in loop_seqs[hidx]:
- vloops.append(s[pidx])
- total_vlen = _get_loop_vert_len(vloops)
- accum_vlens = _get_loop_vert_accum_len(vloops)
- total_uvlen = _get_loop_uv_len(vloops, uv_layer)
- accum_uvlens = _get_loop_uv_accum_len(vloops, uv_layer)
- orig_uvs = [l[uv_layer].uv.copy() for l in vloops]
-
- # calculate target length
- tgt_noinfl = total_uvlen * int((vidx + 1) / 2) * 2 / len(loop_seqs[hidx])
- tgt_infl = total_uvlen * accum_vlens[vidx] / total_vlen
- target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
- common.debug_print(target_length)
- common.debug_print(accum_uvlens)
- print("#### {}".format(tgt_noinfl))
- print("#### {}".format(tgt_infl))
-
- # calculate target UV
- for i in range(len(accum_uvlens[:-1])):
- # get line segment which UV will be placed
- if ((accum_uvlens[i] <= target_length) and
- (accum_uvlens[i + 1] > target_length)):
- tgt_seg_len = target_length - accum_uvlens[i]
- seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
- uv1 = orig_uvs[i]
- uv2 = orig_uvs[i + 1]
- target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
- break
- elif i == (len(accum_uvlens[:-1]) - 1):
- if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
- raise Exception("Internal Error: horizontal_target_length={}"
- " is not equal to {}"
- .format(target_length, accum_uvlens[-1]))
- tgt_seg_len = target_length - accum_uvlens[i]
- seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
- uv1 = orig_uvs[i]
- uv2 = orig_uvs[i + 1]
- target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
- break
- else:
- raise Exception("Internal Error: horizontal_target_length={}"
- " is not in range {} to {}"
- .format(target_length, accum_uvlens[0],
- accum_uvlens[-1]))
-
- return target_uv
-
-
-# get horizontal differential of UV no influenced
-def _get_hdiff_uv(uv_layer, loop_seqs, hidx):
- base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
- h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
-
- return hidx * h_uv / len(loop_seqs)
-
-
-# get vertical differential of UV no influenced
-def _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx):
- base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
- v_uv = loop_seqs[0][-1][0][uv_layer].uv.copy() - base_uv
-
- hseq = loop_seqs[hidx]
- return int((vidx + 1) / 2) * v_uv / (len(hseq) / 2)
-
-
-class StraightenImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- # selected and paralleled UV loop sequence will be aligned
- def __align_w_transmission(self, ops_obj, loop_seqs, uv_layer):
- base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-
- # calculate diff UVs
- diff_uvs = []
- # hseq[vertical][loop]
- for hidx, hseq in enumerate(loop_seqs):
- # pair[loop]
- diffs = []
- for vidx in range(0, len(hseq), 2):
- if ops_obj.horizontal:
- hdiff_uvs = [
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
- ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
- ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 0, ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 1, ops_obj.mesh_infl),
- ]
- else:
- hdiff_uvs = [
- _get_hdiff_uv(uv_layer, loop_seqs, hidx),
- _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1),
- _get_hdiff_uv(uv_layer, loop_seqs, hidx),
- _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1)
- ]
- if ops_obj.vertical:
- vdiff_uvs = [
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
- ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
- ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 0, ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 1, ops_obj.mesh_infl),
- ]
- else:
- vdiff_uvs = [
- _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
- ]
- diffs.append([hdiff_uvs, vdiff_uvs])
- diff_uvs.append(diffs)
-
- # update UV
- for hseq, diffs in zip(loop_seqs, diff_uvs):
- for vidx in range(0, len(hseq), 2):
- loops = [
- hseq[vidx][0], hseq[vidx][1],
- hseq[vidx + 1][0], hseq[vidx + 1][1]
- ]
- for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
- diffs[int(vidx / 2)][1]):
- l[uv_layer].uv = base_uv + hdiff + vdiff
- if ops_obj.select:
- l[uv_layer].select = True
-
- # only selected UV loop sequence will be aligned
- def __align_wo_transmission(self, ops_obj, loop_seqs, uv_layer):
- base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
-
- h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
- for hidx, hseq in enumerate(loop_seqs):
- # only selected loop pair is targeted
- pair = hseq[0]
- hdiff_uv_0 = hidx * h_uv / len(loop_seqs)
- hdiff_uv_1 = (hidx + 1) * h_uv / len(loop_seqs)
- pair[0][uv_layer].uv = base_uv + hdiff_uv_0
- pair[1][uv_layer].uv = base_uv + hdiff_uv_1
- if ops_obj.select:
- pair[0][uv_layer].select = True
- pair[1][uv_layer].select = True
-
- def __align(self, ops_obj, loop_seqs, uv_layer):
- if ops_obj.transmission:
- self.__align_w_transmission(ops_obj, loop_seqs, uv_layer)
- else:
- self.__align_wo_transmission(ops_obj, loop_seqs, uv_layer)
-
- def execute(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- uv_layer = bm.loops.layers.uv.verify()
-
- # loop_seqs[horizontal][vertical][loop]
- loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
- if not loop_seqs:
- ops_obj.report({'WARNING'}, error)
- return {'CANCELLED'}
-
- # align
- self.__align(ops_obj, loop_seqs, uv_layer)
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
-
-
-class AxisImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- # get min/max of UV
- def __get_uv_max_min(self, _, loop_seqs, uv_layer):
- uv_max = Vector((-1000000.0, -1000000.0))
- uv_min = Vector((1000000.0, 1000000.0))
- for hseq in loop_seqs:
- for l in hseq[0]:
- uv = l[uv_layer].uv
- uv_max.x = max(uv.x, uv_max.x)
- uv_max.y = max(uv.y, uv_max.y)
- uv_min.x = min(uv.x, uv_min.x)
- uv_min.y = min(uv.y, uv_min.y)
-
- return uv_max, uv_min
-
- # get UV differentiation when UVs are aligned to X-axis
- def __get_x_axis_align_diff_uvs(self, ops_obj, loop_seqs, uv_layer, uv_min,
- width, height):
- diff_uvs = []
- for hidx, hseq in enumerate(loop_seqs):
- pair = hseq[0]
- luv0 = pair[0][uv_layer]
- luv1 = pair[1][uv_layer]
- target_uv0 = Vector((0.0, 0.0))
- target_uv1 = Vector((0.0, 0.0))
- if ops_obj.location == 'RIGHT_BOTTOM':
- target_uv0.y = target_uv1.y = uv_min.y
- elif ops_obj.location == 'MIDDLE':
- target_uv0.y = target_uv1.y = uv_min.y + height * 0.5
- elif ops_obj.location == 'LEFT_TOP':
- target_uv0.y = target_uv1.y = uv_min.y + height
- if luv0.uv.x < luv1.uv.x:
- target_uv0.x = uv_min.x + hidx * width / len(loop_seqs)
- target_uv1.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
- else:
- target_uv0.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
- target_uv1.x = uv_min.x + hidx * width / len(loop_seqs)
- diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
-
- return diff_uvs
-
- # get UV differentiation when UVs are aligned to Y-axis
- def __get_y_axis_align_diff_uvs(self, ops_obj, loop_seqs, uv_layer, uv_min,
- width, height):
- diff_uvs = []
- for hidx, hseq in enumerate(loop_seqs):
- pair = hseq[0]
- luv0 = pair[0][uv_layer]
- luv1 = pair[1][uv_layer]
- target_uv0 = Vector((0.0, 0.0))
- target_uv1 = Vector((0.0, 0.0))
- if ops_obj.location == 'RIGHT_BOTTOM':
- target_uv0.x = target_uv1.x = uv_min.x + width
- elif ops_obj.location == 'MIDDLE':
- target_uv0.x = target_uv1.x = uv_min.x + width * 0.5
- elif ops_obj.location == 'LEFT_TOP':
- target_uv0.x = target_uv1.x = uv_min.x
- if luv0.uv.y < luv1.uv.y:
- target_uv0.y = uv_min.y + hidx * height / len(loop_seqs)
- target_uv1.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
- else:
- target_uv0.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
- target_uv1.y = uv_min.y + hidx * height / len(loop_seqs)
- diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
-
- return diff_uvs
-
- # only selected UV loop sequence will be aligned along to X-axis
- def __align_to_x_axis_wo_transmission(self, ops_obj, loop_seqs, uv_layer,
- uv_min, width, height):
- # reverse if the UV coordinate is not sorted by position
- need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
- loop_seqs[-1][0][0][uv_layer].uv.x
- if need_revese:
- loop_seqs.reverse()
- for hidx, hseq in enumerate(loop_seqs):
- for vidx, pair in enumerate(hseq):
- tmp = loop_seqs[hidx][vidx][0]
- loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
- loop_seqs[hidx][vidx][1] = tmp
-
- # get UV differential
- diff_uvs = self.__get_x_axis_align_diff_uvs(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
-
- # update UV
- for hseq, duv in zip(loop_seqs, diff_uvs):
- pair = hseq[0]
- luv0 = pair[0][uv_layer]
- luv1 = pair[1][uv_layer]
- luv0.uv = luv0.uv + duv[0]
- luv1.uv = luv1.uv + duv[1]
-
- # only selected UV loop sequence will be aligned along to Y-axis
- def __align_to_y_axis_wo_transmission(self, ops_obj, loop_seqs, uv_layer,
- uv_min, width, height):
- # reverse if the UV coordinate is not sorted by position
- need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
- loop_seqs[-1][0][0][uv_layer].uv.y
- if need_revese:
- loop_seqs.reverse()
- for hidx, hseq in enumerate(loop_seqs):
- for vidx, pair in enumerate(hseq):
- tmp = loop_seqs[hidx][vidx][0]
- loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
- loop_seqs[hidx][vidx][1] = tmp
-
- # get UV differential
- diff_uvs = self.__get_y_axis_align_diff_uvs(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
-
- # update UV
- for hseq, duv in zip(loop_seqs, diff_uvs):
- pair = hseq[0]
- luv0 = pair[0][uv_layer]
- luv1 = pair[1][uv_layer]
- luv0.uv = luv0.uv + duv[0]
- luv1.uv = luv1.uv + duv[1]
-
- # selected and paralleled UV loop sequence will be aligned along to X-axis
- def __align_to_x_axis_w_transmission(self, ops_obj, loop_seqs, uv_layer,
- uv_min, width, height):
- # reverse if the UV coordinate is not sorted by position
- need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
- loop_seqs[-1][0][0][uv_layer].uv.x
- if need_revese:
- loop_seqs.reverse()
- for hidx, hseq in enumerate(loop_seqs):
- for vidx in range(len(hseq)):
- tmp = loop_seqs[hidx][vidx][0]
- loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
- loop_seqs[hidx][vidx][1] = tmp
-
- # get offset UVs when the UVs are aligned to X-axis
- align_diff_uvs = self.__get_x_axis_align_diff_uvs(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
- base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
- offset_uvs = []
- for hseq, aduv in zip(loop_seqs, align_diff_uvs):
- luv0 = hseq[0][0][uv_layer]
- luv1 = hseq[0][1][uv_layer]
- offset_uvs.append([luv0.uv + aduv[0] - base_uv,
- luv1.uv + aduv[1] - base_uv])
-
- # get UV differential
- diff_uvs = []
- # hseq[vertical][loop]
- for hidx, hseq in enumerate(loop_seqs):
- # pair[loop]
- diffs = []
- for vidx in range(0, len(hseq), 2):
- if ops_obj.horizontal:
- hdiff_uvs = [
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
- ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
- ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 0, ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 1, ops_obj.mesh_infl),
- ]
- hdiff_uvs[0].y = hdiff_uvs[0].y + offset_uvs[hidx][0].y
- hdiff_uvs[1].y = hdiff_uvs[1].y + offset_uvs[hidx][1].y
- hdiff_uvs[2].y = hdiff_uvs[2].y + offset_uvs[hidx][0].y
- hdiff_uvs[3].y = hdiff_uvs[3].y + offset_uvs[hidx][1].y
- else:
- hdiff_uvs = [
- offset_uvs[hidx][0],
- offset_uvs[hidx][1],
- offset_uvs[hidx][0],
- offset_uvs[hidx][1],
- ]
- if ops_obj.vertical:
- vdiff_uvs = [
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
- ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
- ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 0, ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 1, ops_obj.mesh_infl),
- ]
- else:
- vdiff_uvs = [
- _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
- ]
- diffs.append([hdiff_uvs, vdiff_uvs])
- diff_uvs.append(diffs)
-
- # update UV
- for hseq, diffs in zip(loop_seqs, diff_uvs):
- for vidx in range(0, len(hseq), 2):
- loops = [
- hseq[vidx][0], hseq[vidx][1],
- hseq[vidx + 1][0], hseq[vidx + 1][1]
- ]
- for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
- diffs[int(vidx / 2)][1]):
- l[uv_layer].uv = base_uv + hdiff + vdiff
- if ops_obj.select:
- l[uv_layer].select = True
-
- # selected and paralleled UV loop sequence will be aligned along to Y-axis
- def __align_to_y_axis_w_transmission(self, ops_obj, loop_seqs, uv_layer,
- uv_min, width, height):
- # reverse if the UV coordinate is not sorted by position
- need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
- loop_seqs[-1][0][-1][uv_layer].uv.y
- if need_revese:
- loop_seqs.reverse()
- for hidx, hseq in enumerate(loop_seqs):
- for vidx in range(len(hseq)):
- tmp = loop_seqs[hidx][vidx][0]
- loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
- loop_seqs[hidx][vidx][1] = tmp
-
- # get offset UVs when the UVs are aligned to Y-axis
- align_diff_uvs = self.__get_y_axis_align_diff_uvs(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
- base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
- offset_uvs = []
- for hseq, aduv in zip(loop_seqs, align_diff_uvs):
- luv0 = hseq[0][0][uv_layer]
- luv1 = hseq[0][1][uv_layer]
- offset_uvs.append([luv0.uv + aduv[0] - base_uv,
- luv1.uv + aduv[1] - base_uv])
-
- # get UV differential
- diff_uvs = []
- # hseq[vertical][loop]
- for hidx, hseq in enumerate(loop_seqs):
- # pair[loop]
- diffs = []
- for vidx in range(0, len(hseq), 2):
- if ops_obj.horizontal:
- hdiff_uvs = [
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
- ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
- ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 0, ops_obj.mesh_infl),
- _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 1, ops_obj.mesh_infl),
- ]
- hdiff_uvs[0].x = hdiff_uvs[0].x + offset_uvs[hidx][0].x
- hdiff_uvs[1].x = hdiff_uvs[1].x + offset_uvs[hidx][1].x
- hdiff_uvs[2].x = hdiff_uvs[2].x + offset_uvs[hidx][0].x
- hdiff_uvs[3].x = hdiff_uvs[3].x + offset_uvs[hidx][1].x
- else:
- hdiff_uvs = [
- offset_uvs[hidx][0],
- offset_uvs[hidx][1],
- offset_uvs[hidx][0],
- offset_uvs[hidx][1],
- ]
- if ops_obj.vertical:
- vdiff_uvs = [
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
- ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
- ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 0, ops_obj.mesh_infl),
- _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
- hidx, 1, ops_obj.mesh_infl),
- ]
- else:
- vdiff_uvs = [
- _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
- _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
- ]
- diffs.append([hdiff_uvs, vdiff_uvs])
- diff_uvs.append(diffs)
-
- # update UV
- for hseq, diffs in zip(loop_seqs, diff_uvs):
- for vidx in range(0, len(hseq), 2):
- loops = [
- hseq[vidx][0], hseq[vidx][1],
- hseq[vidx + 1][0], hseq[vidx + 1][1]
- ]
- for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
- diffs[int(vidx / 2)][1]):
- l[uv_layer].uv = base_uv + hdiff + vdiff
- if ops_obj.select:
- l[uv_layer].select = True
-
- def __align(self, ops_obj, loop_seqs, uv_layer, uv_min, width, height):
- # align along to x-axis
- if width > height:
- if ops_obj.transmission:
- self.__align_to_x_axis_w_transmission(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
- else:
- self.__align_to_x_axis_wo_transmission(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
- # align along to y-axis
- else:
- if ops_obj.transmission:
- self.__align_to_y_axis_w_transmission(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
- else:
- self.__align_to_y_axis_wo_transmission(ops_obj, loop_seqs,
- uv_layer, uv_min,
- width, height)
-
- def execute(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- uv_layer = bm.loops.layers.uv.verify()
-
- # loop_seqs[horizontal][vertical][loop]
- loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
- if not loop_seqs:
- ops_obj.report({'WARNING'}, error)
- return {'CANCELLED'}
-
- # get height and width
- uv_max, uv_min = self.__get_uv_max_min(ops_obj, loop_seqs, uv_layer)
- width = uv_max.x - uv_min.x
- height = uv_max.y - uv_min.y
-
- self.__align(ops_obj, loop_seqs, uv_layer, uv_min, width, height)
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/copy_paste_uv_impl.py b/uv_magic_uv/impl/copy_paste_uv_impl.py
deleted file mode 100644
index ed44637b..00000000
--- a/uv_magic_uv/impl/copy_paste_uv_impl.py
+++ /dev/null
@@ -1,271 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-import bmesh
-
-from .. import common
-
-
-__all__ = [
- 'is_valid_context',
- 'get_copy_uv_layers',
- 'get_paste_uv_layers',
- 'get_src_face_info',
- 'get_dest_face_info',
- 'get_select_history_src_face_info',
- 'get_select_history_dest_face_info',
- 'paste_uv',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def get_copy_uv_layers(ops_obj, bm, uv_map):
- uv_layers = []
- if uv_map == "__default":
- if not bm.loops.layers.uv:
- ops_obj.report(
- {'WARNING'}, "Object must have more than one UV map")
- return None
- uv_layers.append(bm.loops.layers.uv.verify())
- ops_obj.report({'INFO'}, "Copy UV coordinate")
- elif uv_map == "__all":
- for uv in bm.loops.layers.uv.keys():
- uv_layers.append(bm.loops.layers.uv[uv])
- ops_obj.report({'INFO'}, "Copy UV coordinate (UV map: ALL)")
- else:
- uv_layers.append(bm.loops.layers.uv[uv_map])
- ops_obj.report(
- {'INFO'}, "Copy UV coordinate (UV map:{})".format(uv_map))
-
- return uv_layers
-
-
-def get_paste_uv_layers(ops_obj, obj, bm, src_info, uv_map):
- uv_layers = []
- if uv_map == "__default":
- if not bm.loops.layers.uv:
- ops_obj.report(
- {'WARNING'}, "Object must have more than one UV map")
- return None
- uv_layers.append(bm.loops.layers.uv.verify())
- ops_obj.report({'INFO'}, "Paste UV coordinate")
- elif uv_map == "__new":
- new_uv_map = common.create_new_uv_map(obj)
- if not new_uv_map:
- ops_obj.report({'WARNING'},
- "Reached to the maximum number of UV map")
- return None
- uv_layers.append(bm.loops.layers.uv[new_uv_map.name])
- ops_obj.report(
- {'INFO'}, "Paste UV coordinate (UV map:{})".format(new_uv_map))
- elif uv_map == "__all":
- for src_layer in src_info.keys():
- if src_layer not in bm.loops.layers.uv.keys():
- new_uv_map = common.create_new_uv_map(obj, src_layer)
- if not new_uv_map:
- ops_obj.report({'WARNING'},
- "Reached to the maximum number of UV map")
- return None
- uv_layers.append(bm.loops.layers.uv[src_layer])
- ops_obj.report({'INFO'}, "Paste UV coordinate (UV map: ALL)")
- else:
- uv_layers.append(bm.loops.layers.uv[uv_map])
- ops_obj.report(
- {'INFO'}, "Paste UV coordinate (UV map:{})".format(uv_map))
-
- return uv_layers
-
-
-def get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
- src_info = {}
- for layer in uv_layers:
- face_info = []
- for face in bm.faces:
- if not only_select or face.select:
- info = {
- "index": face.index,
- "uvs": [l[layer].uv.copy() for l in face.loops],
- "pin_uvs": [l[layer].pin_uv for l in face.loops],
- "seams": [l.edge.seam for l in face.loops],
- }
- face_info.append(info)
- if not face_info:
- ops_obj.report({'WARNING'}, "No faces are selected")
- return None
- src_info[layer.name] = face_info
-
- return src_info
-
-
-def get_dest_face_info(ops_obj, bm, uv_layers, src_info, strategy,
- only_select=False):
- dest_info = {}
- for layer in uv_layers:
- face_info = []
- for face in bm.faces:
- if not only_select or face.select:
- info = {
- "index": face.index,
- "uvs": [l[layer].uv.copy() for l in face.loops],
- }
- face_info.append(info)
- if not face_info:
- ops_obj.report({'WARNING'}, "No faces are selected")
- return None
- key = list(src_info.keys())[0]
- src_face_count = len(src_info[key])
- dest_face_count = len(face_info)
- if strategy == 'N_N' and src_face_count != dest_face_count:
- ops_obj.report(
- {'WARNING'},
- "Number of selected faces is different from copied" +
- "(src:{}, dest:{})"
- .format(src_face_count, dest_face_count))
- return None
- dest_info[layer.name] = face_info
-
- return dest_info
-
-
-def get_select_history_src_face_info(ops_obj, bm, uv_layers):
- src_info = {}
- for layer in uv_layers:
- face_info = []
- for hist in bm.select_history:
- if isinstance(hist, bmesh.types.BMFace) and hist.select:
- info = {
- "index": hist.index,
- "uvs": [l[layer].uv.copy() for l in hist.loops],
- "pin_uvs": [l[layer].pin_uv for l in hist.loops],
- "seams": [l.edge.seam for l in hist.loops],
- }
- face_info.append(info)
- if not face_info:
- ops_obj.report({'WARNING'}, "No faces are selected")
- return None
- src_info[layer.name] = face_info
-
- return src_info
-
-
-def get_select_history_dest_face_info(ops_obj, bm, uv_layers, src_info,
- strategy):
- dest_info = {}
- for layer in uv_layers:
- face_info = []
- for hist in bm.select_history:
- if isinstance(hist, bmesh.types.BMFace) and hist.select:
- info = {
- "index": hist.index,
- "uvs": [l[layer].uv.copy() for l in hist.loops],
- }
- face_info.append(info)
- if not face_info:
- ops_obj.report({'WARNING'}, "No faces are selected")
- return None
- key = list(src_info.keys())[0]
- src_face_count = len(src_info[key])
- dest_face_count = len(face_info)
- if strategy == 'N_N' and src_face_count != dest_face_count:
- ops_obj.report(
- {'WARNING'},
- "Number of selected faces is different from copied" +
- "(src:{}, dest:{})"
- .format(src_face_count, dest_face_count))
- return None
- dest_info[layer.name] = face_info
-
- return dest_info
-
-
-def paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
- rotate, copy_seams):
- for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
- src_faces = src_info[slayer_name]
- dest_faces = dest_info[dlayer.name]
-
- for idx, dinfo in enumerate(dest_faces):
- sinfo = None
- if strategy == 'N_N':
- sinfo = src_faces[idx]
- elif strategy == 'N_M':
- sinfo = src_faces[idx % len(src_faces)]
-
- suv = sinfo["uvs"]
- spuv = sinfo["pin_uvs"]
- ss = sinfo["seams"]
- if len(sinfo["uvs"]) != len(dinfo["uvs"]):
- ops_obj.report({'WARNING'}, "Some faces are different size")
- return -1
-
- suvs_fr = [uv for uv in suv]
- spuvs_fr = [pin_uv for pin_uv in spuv]
- ss_fr = [s for s in ss]
-
- # flip UVs
- if flip is True:
- suvs_fr.reverse()
- spuvs_fr.reverse()
- ss_fr.reverse()
-
- # rotate UVs
- for _ in range(rotate):
- uv = suvs_fr.pop()
- pin_uv = spuvs_fr.pop()
- s = ss_fr.pop()
- suvs_fr.insert(0, uv)
- spuvs_fr.insert(0, pin_uv)
- ss_fr.insert(0, s)
-
- # paste UVs
- for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
- suvs_fr, spuvs_fr, ss_fr):
- l[dlayer].uv = suv
- l[dlayer].pin_uv = spuv
- if copy_seams is True:
- l.edge.seam = ss
-
- return 0
diff --git a/uv_magic_uv/impl/copy_paste_uv_uvedit_impl.py b/uv_magic_uv/impl/copy_paste_uv_uvedit_impl.py
deleted file mode 100644
index f14a70d6..00000000
--- a/uv_magic_uv/impl/copy_paste_uv_uvedit_impl.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import math
-from math import atan2, sin, cos
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
- 'is_valid_context',
- 'CopyUVImpl',
- 'PasteUVImpl',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
-
-
-class CopyUVImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return is_valid_context(context)
-
- def execute(self, _, context):
- props = context.scene.muv_props.copy_paste_uv_uvedit
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- props.src_uvs = []
- for face in bm.faces:
- if not face.select:
- continue
- skip = False
- for l in face.loops:
- if not l[uv_layer].select:
- skip = True
- break
- if skip:
- continue
- props.src_uvs.append([l[uv_layer].uv.copy() for l in face.loops])
-
- return {'FINISHED'}
-
-
-class PasteUVImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- sc = context.scene
- props = sc.muv_props.copy_paste_uv_uvedit
- if not props.src_uvs:
- return False
- return is_valid_context(context)
-
- def execute(self, _, context):
- props = context.scene.muv_props.copy_paste_uv_uvedit
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- dest_uvs = []
- dest_face_indices = []
- for face in bm.faces:
- if not face.select:
- continue
- skip = False
- for l in face.loops:
- if not l[uv_layer].select:
- skip = True
- break
- if skip:
- continue
- dest_face_indices.append(face.index)
- uvs = [l[uv_layer].uv.copy() for l in face.loops]
- dest_uvs.append(uvs)
-
- for suvs, duvs in zip(props.src_uvs, dest_uvs):
- src_diff = suvs[1] - suvs[0]
- dest_diff = duvs[1] - duvs[0]
-
- src_base = suvs[0]
- dest_base = duvs[0]
-
- src_rad = atan2(src_diff.y, src_diff.x)
- dest_rad = atan2(dest_diff.y, dest_diff.x)
- if src_rad < dest_rad:
- radian = dest_rad - src_rad
- elif src_rad > dest_rad:
- radian = math.pi * 2 - (src_rad - dest_rad)
- else: # src_rad == dest_rad
- radian = 0.0
-
- ratio = dest_diff.length / src_diff.length
- break
-
- for suvs, fidx in zip(props.src_uvs, dest_face_indices):
- for l, suv in zip(bm.faces[fidx].loops, suvs):
- base = suv - src_base
- radian_ref = atan2(base.y, base.x)
- radian_fin = (radian + radian_ref)
- length = base.length
- turn = Vector((length * cos(radian_fin),
- length * sin(radian_fin)))
- target_uv = Vector((turn.x * ratio, turn.y * ratio)) + \
- dest_base
- l[uv_layer].uv = target_uv
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/flip_rotate_impl.py b/uv_magic_uv/impl/flip_rotate_impl.py
deleted file mode 100644
index f74bc256..00000000
--- a/uv_magic_uv/impl/flip_rotate_impl.py
+++ /dev/null
@@ -1,133 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-__all__ = [
- 'is_valid_context',
- 'get_uv_layer',
- 'get_src_face_info',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def get_uv_layer(ops_obj, bm):
- # get UV layer
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'}, "Object must have more than one UV map")
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- return uv_layer
-
-
-def get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
- src_info = {}
- for layer in uv_layers:
- face_info = []
- for face in bm.faces:
- if not only_select or face.select:
- info = {
- "index": face.index,
- "uvs": [l[layer].uv.copy() for l in face.loops],
- "pin_uvs": [l[layer].pin_uv for l in face.loops],
- "seams": [l.edge.seam for l in face.loops],
- }
- face_info.append(info)
- if not face_info:
- ops_obj.report({'WARNING'}, "No faces are selected")
- return None
- src_info[layer.name] = face_info
-
- return src_info
-
-
-def paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
- rotate, copy_seams):
- for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
- src_faces = src_info[slayer_name]
- dest_faces = dest_info[dlayer.name]
-
- for idx, dinfo in enumerate(dest_faces):
- sinfo = None
- if strategy == 'N_N':
- sinfo = src_faces[idx]
- elif strategy == 'N_M':
- sinfo = src_faces[idx % len(src_faces)]
-
- suv = sinfo["uvs"]
- spuv = sinfo["pin_uvs"]
- ss = sinfo["seams"]
- if len(sinfo["uvs"]) != len(dinfo["uvs"]):
- ops_obj.report({'WARNING'}, "Some faces are different size")
- return -1
-
- suvs_fr = [uv for uv in suv]
- spuvs_fr = [pin_uv for pin_uv in spuv]
- ss_fr = [s for s in ss]
-
- # flip UVs
- if flip is True:
- suvs_fr.reverse()
- spuvs_fr.reverse()
- ss_fr.reverse()
-
- # rotate UVs
- for _ in range(rotate):
- uv = suvs_fr.pop()
- pin_uv = spuvs_fr.pop()
- s = ss_fr.pop()
- suvs_fr.insert(0, uv)
- spuvs_fr.insert(0, pin_uv)
- ss_fr.insert(0, s)
-
- # paste UVs
- for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
- suvs_fr, spuvs_fr, ss_fr):
- l[dlayer].uv = suv
- l[dlayer].pin_uv = spuv
- if copy_seams is True:
- l.edge.seam = ss
-
- return 0
diff --git a/uv_magic_uv/impl/mirror_uv_impl.py b/uv_magic_uv/impl/mirror_uv_impl.py
deleted file mode 100644
index e79fbc2c..00000000
--- a/uv_magic_uv/impl/mirror_uv_impl.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# <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__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
- 'is_valid_context',
- 'is_vector_similar',
- 'mirror_uvs',
- 'get_face_center',
- 'MirrorUVImpl',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def is_vector_similar(v1, v2, error):
- """
- Check if two vectors are similar, within an error threshold
- """
- within_err_x = abs(v2.x - v1.x) < error
- within_err_y = abs(v2.y - v1.y) < error
- within_err_z = abs(v2.z - v1.z) < error
-
- return within_err_x and within_err_y and within_err_z
-
-
-def mirror_uvs(uv_layer, src, dst, axis, error):
- """
- Copy UV coordinates from one UV face to another
- """
- for sl in src.loops:
- suv = sl[uv_layer].uv.copy()
- svco = sl.vert.co.copy()
- for dl in dst.loops:
- dvco = dl.vert.co.copy()
- if axis == 'X':
- dvco.x = -dvco.x
- elif axis == 'Y':
- dvco.y = -dvco.y
- elif axis == 'Z':
- dvco.z = -dvco.z
-
- if is_vector_similar(svco, dvco, error):
- dl[uv_layer].uv = suv.copy()
-
-
-def get_face_center(face):
- """
- Get center coordinate of the face
- """
- center = Vector((0.0, 0.0, 0.0))
- for v in face.verts:
- center = center + v.co
-
- return center / len(face.verts)
-
-
-class MirrorUVImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return is_valid_context(context)
-
- def execute(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
-
- error = ops_obj.error
- axis = ops_obj.axis
-
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
-
- faces = [f for f in bm.faces if f.select]
- for f_dst in faces:
- count = len(f_dst.verts)
- for f_src in bm.faces:
- # check if this is a candidate to do mirror UV
- if f_src.index == f_dst.index:
- continue
- if count != len(f_src.verts):
- continue
-
- # test if the vertices x values are the same sign
- dst = get_face_center(f_dst)
- src = get_face_center(f_src)
- if (dst.x > 0 and src.x > 0) or (dst.x < 0 and src.x < 0):
- continue
-
- # invert source axis
- if axis == 'X':
- src.x = -src.x
- elif axis == 'Y':
- src.y = -src.z
- elif axis == 'Z':
- src.z = -src.z
-
- # do mirror UV
- if is_vector_similar(dst, src, error):
- mirror_uvs(
- uv_layer, f_src, f_dst, ops_obj.axis, ops_obj.error)
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/move_uv_impl.py b/uv_magic_uv/impl/move_uv_impl.py
deleted file mode 100644
index ce507fba..00000000
--- a/uv_magic_uv/impl/move_uv_impl.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
- 'is_valid_context',
- 'find_uv',
- 'MoveUVImpl',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def find_uv(context):
- bm = bmesh.from_edit_mesh(context.object.data)
- topology_dict = []
- uvs = []
- active_uv = bm.loops.layers.uv.active
- for fidx, f in enumerate(bm.faces):
- for vidx, v in enumerate(f.verts):
- if v.select:
- uvs.append(f.loops[vidx][active_uv].uv.copy())
- topology_dict.append([fidx, vidx])
-
- return topology_dict, uvs
-
-
-class MoveUVImpl():
- __running = False
-
- def __init__(self):
- self.__topology_dict = []
- self.__prev_mouse = Vector((0.0, 0.0))
- self.__offset_uv = Vector((0.0, 0.0))
- self.__prev_offset_uv = Vector((0.0, 0.0))
- self.__first_time = True
- self.__ini_uvs = []
- self.__operating = False
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return False
- if cls.is_running(context):
- return False
- return is_valid_context(context)
-
- @classmethod
- def is_running(cls, _):
- return cls.__running
-
- def modal(self, _, context, event):
- if self.__first_time is True:
- self.__prev_mouse = Vector((
- event.mouse_region_x, event.mouse_region_y))
- self.__first_time = False
- return {'RUNNING_MODAL'}
-
- # move UV
- div = 10000
- self.__offset_uv += Vector((
- (event.mouse_region_x - self.__prev_mouse.x) / div,
- (event.mouse_region_y - self.__prev_mouse.y) / div))
- ouv = self.__offset_uv
- pouv = self.__prev_offset_uv
- vec = Vector((ouv.x - ouv.y, ouv.x + ouv.y))
- dv = vec - pouv
- self.__prev_offset_uv = vec
- self.__prev_mouse = Vector((
- event.mouse_region_x, event.mouse_region_y))
-
- # check if operation is started
- if not self.__operating:
- if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
- self.__operating = True
- return {'RUNNING_MODAL'}
-
- # update UV
- obj = context.object
- bm = bmesh.from_edit_mesh(obj.data)
- active_uv = bm.loops.layers.uv.active
- for fidx, vidx in self.__topology_dict:
- l = bm.faces[fidx].loops[vidx]
- l[active_uv].uv = l[active_uv].uv + dv
- bmesh.update_edit_mesh(obj.data)
-
- # check mouse preference
- if context.user_preferences.inputs.select_mouse == 'RIGHT':
- confirm_btn = 'LEFTMOUSE'
- cancel_btn = 'RIGHTMOUSE'
- else:
- confirm_btn = 'RIGHTMOUSE'
- cancel_btn = 'LEFTMOUSE'
-
- # cancelled
- if event.type == cancel_btn and event.value == 'PRESS':
- for (fidx, vidx), uv in zip(self.__topology_dict, self.__ini_uvs):
- bm.faces[fidx].loops[vidx][active_uv].uv = uv
- MoveUVImpl.__running = False
- return {'FINISHED'}
- # confirmed
- if event.type == confirm_btn and event.value == 'PRESS':
- MoveUVImpl.__running = False
- return {'FINISHED'}
-
- return {'RUNNING_MODAL'}
-
- def execute(self, ops_obj, context):
- MoveUVImpl.__running = True
- self.__operating = False
- self.__first_time = True
-
- context.window_manager.modal_handler_add(ops_obj)
- self.__topology_dict, self.__ini_uvs = find_uv(context)
-
- if context.area:
- context.area.tag_redraw()
-
- return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/impl/pack_uv_impl.py b/uv_magic_uv/impl/pack_uv_impl.py
deleted file mode 100644
index 49f954f3..00000000
--- a/uv_magic_uv/impl/pack_uv_impl.py
+++ /dev/null
@@ -1,202 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from math import fabs
-
-import bpy
-import bmesh
-import mathutils
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
- 'PackUVImpl',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
-
-
-def sort_island_faces(kd, uvs, isl1, isl2):
- """
- Sort faces in island
- """
-
- sorted_faces = []
- for f in isl1['sorted']:
- _, idx, _ = kd.find(
- Vector((f['ave_uv'].x, f['ave_uv'].y, 0.0)))
- sorted_faces.append(isl2['faces'][uvs[idx]['face_idx']])
- return sorted_faces
-
-
-def group_island(island_info, allowable_center_deviation,
- allowable_size_deviation):
- """
- Group island
- """
-
- num_group = 0
- while True:
- # search islands which is not parsed yet
- isl_1 = None
- for isl_1 in island_info:
- if isl_1['group'] == -1:
- break
- else:
- break # all faces are parsed
- if isl_1 is None:
- break
- isl_1['group'] = num_group
- isl_1['sorted'] = isl_1['faces']
-
- # search same island
- for isl_2 in island_info:
- if isl_2['group'] == -1:
- dcx = isl_2['center'].x - isl_1['center'].x
- dcy = isl_2['center'].y - isl_1['center'].y
- dsx = isl_2['size'].x - isl_1['size'].x
- dsy = isl_2['size'].y - isl_1['size'].y
- center_x_matched = (
- fabs(dcx) < allowable_center_deviation[0]
- )
- center_y_matched = (
- fabs(dcy) < allowable_center_deviation[1]
- )
- size_x_matched = (
- fabs(dsx) < allowable_size_deviation[0]
- )
- size_y_matched = (
- fabs(dsy) < allowable_size_deviation[1]
- )
- center_matched = center_x_matched and center_y_matched
- size_matched = size_x_matched and size_y_matched
- num_uv_matched = (isl_2['num_uv'] == isl_1['num_uv'])
- # are islands have same?
- if center_matched and size_matched and num_uv_matched:
- isl_2['group'] = num_group
- kd = mathutils.kdtree.KDTree(len(isl_2['faces']))
- uvs = [
- {
- 'uv': Vector(
- (f['ave_uv'].x, f['ave_uv'].y, 0.0)
- ),
- 'face_idx': fidx
- } for fidx, f in enumerate(isl_2['faces'])
- ]
- for i, uv in enumerate(uvs):
- kd.insert(uv['uv'], i)
- kd.balance()
- # sort faces for copy/paste UV
- isl_2['sorted'] = sort_island_faces(kd, uvs, isl_1, isl_2)
- num_group = num_group + 1
-
- return num_group
-
-
-class PackUVImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return is_valid_context(context)
-
- def execute(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
-
- selected_faces = [f for f in bm.faces if f.select]
- island_info = common.get_island_info(obj)
- num_group = group_island(island_info,
- ops_obj.allowable_center_deviation,
- ops_obj.allowable_size_deviation)
-
- loop_lists = [l for f in bm.faces for l in f.loops]
- bpy.ops.mesh.select_all(action='DESELECT')
-
- # pack UV
- for gidx in range(num_group):
- group = list(filter(
- lambda i, idx=gidx: i['group'] == idx, island_info))
- for f in group[0]['faces']:
- f['face'].select = True
- bmesh.update_edit_mesh(obj.data)
- bpy.ops.uv.select_all(action='SELECT')
- bpy.ops.uv.pack_islands(rotate=ops_obj.rotate, margin=ops_obj.margin)
-
- # copy/paste UV among same islands
- for gidx in range(num_group):
- group = list(filter(
- lambda i, idx=gidx: i['group'] == idx, island_info))
- if len(group) <= 1:
- continue
- for g in group[1:]:
- for (src_face, dest_face) in zip(
- group[0]['sorted'], g['sorted']):
- for (src_loop, dest_loop) in zip(
- src_face['face'].loops, dest_face['face'].loops):
- loop_lists[dest_loop.index][uv_layer].uv = loop_lists[
- src_loop.index][uv_layer].uv
-
- # restore face/UV selection
- bpy.ops.uv.select_all(action='DESELECT')
- bpy.ops.mesh.select_all(action='DESELECT')
- for f in selected_faces:
- f.select = True
- bpy.ops.uv.select_all(action='SELECT')
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/preserve_uv_aspect_impl.py b/uv_magic_uv/impl/preserve_uv_aspect_impl.py
deleted file mode 100644
index 622ee1d3..00000000
--- a/uv_magic_uv/impl/preserve_uv_aspect_impl.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-__all__ = [
- 'PreserveUVAspectLegacyImpl',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-class PreserveUVAspectLegacyImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return is_valid_context(context)
-
- def execute(self, ops_obj, context):
- # Note: the current system only works if the
- # f[tex_layer].image doesn't return None
- # which will happen in certain cases
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
-
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
-
- uv_layer = bm.loops.layers.uv.verify()
- tex_layer = bm.faces.layers.tex.verify()
-
- sel_faces = [f for f in bm.faces if f.select]
- dest_img = bpy.data.images[ops_obj.dest_img_name]
-
- info = {}
-
- for f in sel_faces:
- if not f[tex_layer].image in info.keys():
- info[f[tex_layer].image] = {}
- info[f[tex_layer].image]['faces'] = []
- info[f[tex_layer].image]['faces'].append(f)
-
- for img in info:
- if img is None:
- continue
-
- src_img = img
- ratio = Vector((
- dest_img.size[0] / src_img.size[0],
- dest_img.size[1] / src_img.size[1]))
-
- if ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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
-
- for img in info:
- if img is None:
- continue
-
- for f in info[img]['faces']:
- f[tex_layer].image = dest_img
- for l in f.loops:
- uv = l[uv_layer].uv
- 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)
-
- return {'FINISHED'}
-
-
-class PreserveUVAspectImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return is_valid_context(context)
-
- def execute(self, ops_obj, context):
- # Note: the current system only works if the
- # f[tex_layer].image doesn't return None
- # which will happen in certain cases
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
-
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
-
- uv_layer = bm.loops.layers.uv.verify()
- tex_image = common.find_image(obj)
-
- sel_faces = [f for f in bm.faces if f.select]
- dest_img = bpy.data.images[ops_obj.dest_img_name]
-
- info = {}
-
- for f in sel_faces:
- if not tex_image in info.keys():
- info[tex_image] = {}
- info[tex_image]['faces'] = []
- info[tex_image]['faces'].append(f)
-
- for img in info:
- if img is None:
- continue
-
- src_img = img
- ratio = Vector((
- dest_img.size[0] / src_img.size[0],
- dest_img.size[1] / src_img.size[1]))
-
- if ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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 ops_obj.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)
- else:
- ops_obj.report({'ERROR'}, "Unknown Operation")
- return {'CANCELLED'}
-
- info[img]['ratio'] = ratio
- info[img]['origin'] = origin
-
- for img in info:
- if img is None:
- continue
-
- nodes = common.find_texture_nodes(obj)
- nodes[0].image = dest_img
-
- for f in info[img]['faces']:
- for l in f.loops:
- uv = l[uv_layer].uv
- 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)
-
- return {'FINISHED'} \ No newline at end of file
diff --git a/uv_magic_uv/impl/select_uv_impl.py b/uv_magic_uv/impl/select_uv_impl.py
deleted file mode 100644
index dbcaee7e..00000000
--- a/uv_magic_uv/impl/select_uv_impl.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
-
-
-class SelectOverlappedImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, _, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- uv_layer = bm.loops.layers.uv.verify()
-
- if context.tool_settings.use_uv_select_sync:
- sel_faces = [f for f in bm.faces]
- else:
- sel_faces = [f for f in bm.faces if f.select]
-
- overlapped_info = common.get_overlapped_uv_info(bm, sel_faces,
- uv_layer, 'FACE')
-
- for info in overlapped_info:
- if context.tool_settings.use_uv_select_sync:
- info["subject_face"].select = True
- else:
- for l in info["subject_face"].loops:
- l[uv_layer].select = True
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
-
-
-class SelectFlippedImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, _, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- uv_layer = bm.loops.layers.uv.verify()
-
- if context.tool_settings.use_uv_select_sync:
- sel_faces = [f for f in bm.faces]
- else:
- sel_faces = [f for f in bm.faces if f.select]
-
- flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
-
- for info in flipped_info:
- if context.tool_settings.use_uv_select_sync:
- info["face"].select = True
- else:
- for l in info["face"].loops:
- l[uv_layer].select = True
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/smooth_uv_impl.py b/uv_magic_uv/impl/smooth_uv_impl.py
deleted file mode 100644
index dbc8afad..00000000
--- a/uv_magic_uv/impl/smooth_uv_impl.py
+++ /dev/null
@@ -1,215 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
-
-
-class SmoothUVImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def __smooth_wo_transmission(self, ops_obj, loop_seqs, uv_layer):
- # calculate path length
- loops = []
- for hseq in loop_seqs:
- loops.extend([hseq[0][0], hseq[0][1]])
- full_vlen = 0
- accm_vlens = [0.0]
- full_uvlen = 0
- accm_uvlens = [0.0]
- orig_uvs = [loop_seqs[0][0][0][uv_layer].uv.copy()]
- for l1, l2 in zip(loops[:-1], loops[1:]):
- diff_v = l2.vert.co - l1.vert.co
- full_vlen = full_vlen + diff_v.length
- accm_vlens.append(full_vlen)
- diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
- full_uvlen = full_uvlen + diff_uv.length
- accm_uvlens.append(full_uvlen)
- orig_uvs.append(l2[uv_layer].uv.copy())
-
- for hidx, hseq in enumerate(loop_seqs):
- pair = hseq[0]
- for pidx, l in enumerate(pair):
- if ops_obj.select:
- l[uv_layer].select = True
-
- # ignore start/end loop
- if (hidx == 0 and pidx == 0) or\
- ((hidx == len(loop_seqs) - 1) and (pidx == len(pair) - 1)):
- continue
-
- # calculate target path length
- # target = no influenced * (1 - infl) + influenced * infl
- tgt_noinfl = full_uvlen * (hidx + pidx) / (len(loop_seqs))
- tgt_infl = full_uvlen * accm_vlens[hidx * 2 + pidx] / full_vlen
- target_length = tgt_noinfl * (1 - ops_obj.mesh_infl) + \
- tgt_infl * ops_obj.mesh_infl
-
- # get target UV
- for i in range(len(accm_uvlens[:-1])):
- # get line segment which UV will be placed
- if ((accm_uvlens[i] <= target_length) and
- (accm_uvlens[i + 1] > target_length)):
- tgt_seg_len = target_length - accm_uvlens[i]
- seg_len = accm_uvlens[i + 1] - accm_uvlens[i]
- uv1 = orig_uvs[i]
- uv2 = orig_uvs[i + 1]
- target_uv = uv1 + (uv2 - uv1) * tgt_seg_len / seg_len
- break
- else:
- ops_obj.report({'ERROR'}, "Failed to get target UV")
- return {'CANCELLED'}
-
- # update UV
- l[uv_layer].uv = target_uv
-
- def __smooth_w_transmission(self, ops_obj, loop_seqs, uv_layer):
- # calculate path length
- loops = []
- for vidx in range(len(loop_seqs[0])):
- ls = []
- for hseq in loop_seqs:
- ls.extend(hseq[vidx])
- loops.append(ls)
-
- orig_uvs = []
- accm_vlens = []
- full_vlens = []
- accm_uvlens = []
- full_uvlens = []
- for ls in loops:
- full_v = 0.0
- accm_v = [0.0]
- full_uv = 0.0
- accm_uv = [0.0]
- uvs = [ls[0][uv_layer].uv.copy()]
- for l1, l2 in zip(ls[:-1], ls[1:]):
- diff_v = l2.vert.co - l1.vert.co
- full_v = full_v + diff_v.length
- accm_v.append(full_v)
- diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
- full_uv = full_uv + diff_uv.length
- accm_uv.append(full_uv)
- uvs.append(l2[uv_layer].uv.copy())
- accm_vlens.append(accm_v)
- full_vlens.append(full_v)
- accm_uvlens.append(accm_uv)
- full_uvlens.append(full_uv)
- orig_uvs.append(uvs)
-
- for hidx, hseq in enumerate(loop_seqs):
- for vidx, (pair, uvs, accm_v, full_v, accm_uv, full_uv)\
- in enumerate(zip(hseq, orig_uvs, accm_vlens, full_vlens,
- accm_uvlens, full_uvlens)):
- for pidx, l in enumerate(pair):
- if ops_obj.select:
- l[uv_layer].select = True
-
- # ignore start/end loop
- if hidx == 0 and pidx == 0:
- continue
- if hidx == len(loop_seqs) - 1 and pidx == len(pair) - 1:
- continue
-
- # calculate target path length
- # target = no influenced * (1 - infl) + influenced * infl
- tgt_noinfl = full_uv * (hidx + pidx) / (len(loop_seqs))
- tgt_infl = full_uv * accm_v[hidx * 2 + pidx] / full_v
- target_length = tgt_noinfl * (1 - ops_obj.mesh_infl) + \
- tgt_infl * ops_obj.mesh_infl
-
- # get target UV
- for i in range(len(accm_uv[:-1])):
- # get line segment to be placed
- if ((accm_uv[i] <= target_length) and
- (accm_uv[i + 1] > target_length)):
- tgt_seg_len = target_length - accm_uv[i]
- seg_len = accm_uv[i + 1] - accm_uv[i]
- uv1 = uvs[i]
- uv2 = uvs[i + 1]
- target_uv = uv1 +\
- (uv2 - uv1) * tgt_seg_len / seg_len
- break
- else:
- ops_obj.report({'ERROR'}, "Failed to get target UV")
- return {'CANCELLED'}
-
- # update UV
- l[uv_layer].uv = target_uv
-
- def __smooth(self, ops_obj, loop_seqs, uv_layer):
- if ops_obj.transmission:
- self.__smooth_w_transmission(ops_obj, loop_seqs, uv_layer)
- else:
- self.__smooth_wo_transmission(ops_obj, loop_seqs, uv_layer)
-
- def execute(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- uv_layer = bm.loops.layers.uv.verify()
-
- # loop_seqs[horizontal][vertical][loop]
- loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
- if not loop_seqs:
- ops_obj.report({'WARNING'}, error)
- return {'CANCELLED'}
-
- # smooth
- self.__smooth(ops_obj, loop_seqs, uv_layer)
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/texture_lock_impl.py b/uv_magic_uv/impl/texture_lock_impl.py
deleted file mode 100644
index c14eddb0..00000000
--- a/uv_magic_uv/impl/texture_lock_impl.py
+++ /dev/null
@@ -1,455 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import math
-from math import atan2, cos, sqrt, sin, fabs
-
-import bpy
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-def _get_vco(verts_orig, loop):
- """
- Get vertex original coordinate from loop
- """
- for vo in verts_orig:
- if vo["vidx"] == loop.vert.index and vo["moved"] is False:
- return vo["vco"]
- return loop.vert.co
-
-
-def _get_link_loops(vert):
- """
- Get loop linked to vertex
- """
- link_loops = []
- for f in vert.link_faces:
- adj_loops = []
- for loop in f.loops:
- # self loop
- if loop.vert == vert:
- l = loop
- # linked loop
- else:
- for e in loop.vert.link_edges:
- if e.other_vert(loop.vert) == vert:
- adj_loops.append(loop)
- if len(adj_loops) < 2:
- return None
-
- link_loops.append({"l": l, "l0": adj_loops[0], "l1": adj_loops[1]})
- return link_loops
-
-
-def _get_ini_geom(link_loop, uv_layer, verts_orig, v_orig):
- """
- Get initial geometory
- (Get interior angle of face in vertex/UV space)
- """
- u = link_loop["l"][uv_layer].uv
- v0 = _get_vco(verts_orig, link_loop["l0"])
- u0 = link_loop["l0"][uv_layer].uv
- v1 = _get_vco(verts_orig, link_loop["l1"])
- u1 = link_loop["l1"][uv_layer].uv
-
- # get interior angle of face in vertex space
- v0v1 = v1 - v0
- v0v = v_orig["vco"] - v0
- v1v = v_orig["vco"] - v1
- theta0 = v0v1.angle(v0v)
- theta1 = v0v1.angle(-v1v)
- if (theta0 + theta1) > math.pi:
- theta0 = v0v1.angle(-v0v)
- theta1 = v0v1.angle(v1v)
-
- # get interior angle of face in UV space
- u0u1 = u1 - u0
- u0u = u - u0
- u1u = u - u1
- phi0 = u0u1.angle(u0u)
- phi1 = u0u1.angle(-u1u)
- if (phi0 + phi1) > math.pi:
- phi0 = u0u1.angle(-u0u)
- phi1 = u0u1.angle(u1u)
-
- # get direction of linked UV coordinate
- # this will be used to judge whether angle is more or less than 180 degree
- dir0 = u0u1.cross(u0u) > 0
- dir1 = u0u1.cross(u1u) > 0
-
- return {
- "theta0": theta0,
- "theta1": theta1,
- "phi0": phi0,
- "phi1": phi1,
- "dir0": dir0,
- "dir1": dir1}
-
-
-def _get_target_uv(link_loop, uv_layer, verts_orig, v, ini_geom):
- """
- Get target UV coordinate
- """
- v0 = _get_vco(verts_orig, link_loop["l0"])
- lo0 = link_loop["l0"]
- v1 = _get_vco(verts_orig, link_loop["l1"])
- lo1 = link_loop["l1"]
-
- # get interior angle of face in vertex space
- v0v1 = v1 - v0
- v0v = v.co - v0
- v1v = v.co - v1
- theta0 = v0v1.angle(v0v)
- theta1 = v0v1.angle(-v1v)
- if (theta0 + theta1) > math.pi:
- theta0 = v0v1.angle(-v0v)
- theta1 = v0v1.angle(v1v)
-
- # calculate target interior angle in UV space
- phi0 = theta0 * ini_geom["phi0"] / ini_geom["theta0"]
- phi1 = theta1 * ini_geom["phi1"] / ini_geom["theta1"]
-
- uv0 = lo0[uv_layer].uv
- uv1 = lo1[uv_layer].uv
-
- # calculate target vertex coordinate from target interior angle
- tuv0, tuv1 = _calc_tri_vert(uv0, uv1, phi0, phi1)
-
- # target UV coordinate depends on direction, so judge using direction of
- # linked UV coordinate
- u0u1 = uv1 - uv0
- u0u = tuv0 - uv0
- u1u = tuv0 - uv1
- dir0 = u0u1.cross(u0u) > 0
- dir1 = u0u1.cross(u1u) > 0
- if (ini_geom["dir0"] != dir0) or (ini_geom["dir1"] != dir1):
- return tuv1
-
- return tuv0
-
-
-def _calc_tri_vert(v0, v1, angle0, angle1):
- """
- Calculate rest coordinate from other coordinates and angle of end
- """
- angle = math.pi - angle0 - angle1
-
- alpha = atan2(v1.y - v0.y, v1.x - v0.x)
- d = (v1.x - v0.x) / cos(alpha)
- a = d * sin(angle0) / sin(angle)
- b = d * sin(angle1) / sin(angle)
- s = (a + b + d) / 2.0
- if fabs(d) < 0.0000001:
- xd = 0
- yd = 0
- else:
- r = s * (s - a) * (s - b) * (s - d)
- if r < 0:
- xd = 0
- yd = 0
- else:
- xd = (b * b - a * a + d * d) / (2 * d)
- yd = 2 * sqrt(r) / d
- x1 = xd * cos(alpha) - yd * sin(alpha) + v0.x
- y1 = xd * sin(alpha) + yd * cos(alpha) + v0.y
- x2 = xd * cos(alpha) + yd * sin(alpha) + v0.x
- y2 = xd * sin(alpha) - yd * cos(alpha) + v0.y
-
- return Vector((x1, y1)), Vector((x2, y2))
-
-
-def _is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-class LockImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- @classmethod
- def is_ready(cls, context):
- sc = context.scene
- props = sc.muv_props.texture_lock
- if props.verts_orig:
- return True
- return False
-
- def execute(self, ops_obj, context):
- props = context.scene.muv_props.texture_lock
- obj = bpy.context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- ops_obj.report(
- {'WARNING'}, "Object must have more than one UV map")
- return {'CANCELLED'}
-
- props.verts_orig = [
- {"vidx": v.index, "vco": v.co.copy(), "moved": False}
- for v in bm.verts if v.select]
-
- return {'FINISHED'}
-
-
-class UnlockImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- sc = context.scene
- props = sc.muv_props.texture_lock
- if not props.verts_orig:
- return False
- if not LockImpl.is_ready(context):
- return False
- if not _is_valid_context(context):
- return False
- return True
-
- def execute(self, ops_obj, context):
- sc = context.scene
- props = sc.muv_props.texture_lock
- obj = bpy.context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- ops_obj.report(
- {'WARNING'}, "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
-
- verts = [v.index for v in bm.verts if v.select]
- verts_orig = props.verts_orig
-
- # move UV followed by vertex coordinate
- for vidx, v_orig in zip(verts, verts_orig):
- if vidx != v_orig["vidx"]:
- ops_obj.report({'ERROR'}, "Internal Error")
- return {"CANCELLED"}
-
- v = bm.verts[vidx]
- link_loops = _get_link_loops(v)
-
- result = []
-
- for ll in link_loops:
- ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
- target_uv = _get_target_uv(
- ll, uv_layer, verts_orig, v, ini_geom)
- result.append({"l": ll["l"], "uv": target_uv})
-
- # connect other face's UV
- if ops_obj.connect:
- ave = Vector((0.0, 0.0))
- for r in result:
- ave = ave + r["uv"]
- ave = ave / len(result)
- for r in result:
- r["l"][uv_layer].uv = ave
- else:
- for r in result:
- r["l"][uv_layer].uv = r["uv"]
- v_orig["moved"] = True
- bmesh.update_edit_mesh(obj.data)
-
- props.verts_orig = None
-
- return {'FINISHED'}
-
-
-class IntrImpl:
- __timer = None
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return False
- return _is_valid_context(context)
-
- @classmethod
- def is_running(cls, _):
- return 1 if cls.__timer else 0
-
- @classmethod
- def handle_add(cls, ops_obj, context):
- if cls.__timer is None:
- cls.__timer = context.window_manager.event_timer_add(
- 0.10, window=context.window)
- context.window_manager.modal_handler_add(ops_obj)
-
- @classmethod
- def handle_remove(cls, context):
- if cls.__timer is not None:
- context.window_manager.event_timer_remove(cls.__timer)
- cls.__timer = None
-
- def __init__(self):
- self.__intr_verts_orig = []
- self.__intr_verts = []
-
- def __sel_verts_changed(self, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- prev = set(self.__intr_verts)
- now = set([v.index for v in bm.verts if v.select])
-
- return prev != now
-
- def __reinit_verts(self, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- self.__intr_verts_orig = [
- {"vidx": v.index, "vco": v.co.copy(), "moved": False}
- for v in bm.verts if v.select]
- self.__intr_verts = [v.index for v in bm.verts if v.select]
-
- def __update_uv(self, ops_obj, context):
- """
- Update UV when vertex coordinates are changed
- """
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return
- uv_layer = bm.loops.layers.uv.verify()
-
- verts = [v.index for v in bm.verts if v.select]
- verts_orig = self.__intr_verts_orig
-
- for vidx, v_orig in zip(verts, verts_orig):
- if vidx != v_orig["vidx"]:
- ops_obj.report({'ERROR'}, "Internal Error")
- return
-
- v = bm.verts[vidx]
- link_loops = _get_link_loops(v)
-
- result = []
- for ll in link_loops:
- ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
- target_uv = _get_target_uv(
- ll, uv_layer, verts_orig, v, ini_geom)
- result.append({"l": ll["l"], "uv": target_uv})
-
- # UV connect option is always true, because it raises
- # unexpected behavior
- ave = Vector((0.0, 0.0))
- for r in result:
- ave = ave + r["uv"]
- ave = ave / len(result)
- for r in result:
- r["l"][uv_layer].uv = ave
- v_orig["moved"] = True
- bmesh.update_edit_mesh(obj.data)
-
- common.redraw_all_areas()
- self.__intr_verts_orig = [
- {"vidx": v.index, "vco": v.co.copy(), "moved": False}
- for v in bm.verts if v.select]
-
- def modal(self, ops_obj, context, event):
- if not _is_valid_context(context):
- IntrImpl.handle_remove(context)
- return {'FINISHED'}
-
- if not IntrImpl.is_running(context):
- return {'FINISHED'}
-
- if context.area:
- context.area.tag_redraw()
-
- if event.type == 'TIMER':
- if self.__sel_verts_changed(context):
- self.__reinit_verts(context)
- else:
- self.__update_uv(ops_obj, context)
-
- return {'PASS_THROUGH'}
-
- def invoke(self, ops_obj, context, _):
- if not _is_valid_context(context):
- return {'CANCELLED'}
-
- if not IntrImpl.is_running(context):
- IntrImpl.handle_add(ops_obj, context)
- return {'RUNNING_MODAL'}
- else:
- IntrImpl.handle_remove(context)
-
- if context.area:
- context.area.tag_redraw()
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/texture_projection_impl.py b/uv_magic_uv/impl/texture_projection_impl.py
deleted file mode 100644
index b64fa374..00000000
--- a/uv_magic_uv/impl/texture_projection_impl.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from collections import namedtuple
-
-import bpy
-import mathutils
-
-
-_Rect = namedtuple('Rect', 'x0 y0 x1 y1')
-_Rect2 = namedtuple('Rect2', 'x y width height')
-
-
-def get_loaded_texture_name(_, __):
- items = [(key, key, "") for key in bpy.data.images.keys()]
- items.append(("None", "None", ""))
- return items
-
-
-def get_canvas(context, magnitude):
- """
- Get canvas to be renderred texture
- """
- sc = context.scene
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-
- region_w = context.region.width
- region_h = context.region.height
- canvas_w = region_w - prefs.texture_projection_canvas_padding[0] * 2.0
- canvas_h = region_h - prefs.texture_projection_canvas_padding[1] * 2.0
-
- img = bpy.data.images[sc.muv_texture_projection_tex_image]
- tex_w = img.size[0]
- tex_h = img.size[1]
-
- center_x = region_w * 0.5
- center_y = region_h * 0.5
-
- if sc.muv_texture_projection_adjust_window:
- ratio_x = canvas_w / tex_w
- ratio_y = canvas_h / tex_h
- if sc.muv_texture_projection_apply_tex_aspect:
- ratio = ratio_y if ratio_x > ratio_y else ratio_x
- len_x = ratio * tex_w
- len_y = ratio * tex_h
- else:
- len_x = canvas_w
- len_y = canvas_h
- else:
- if sc.muv_texture_projection_apply_tex_aspect:
- len_x = tex_w * magnitude
- len_y = tex_h * magnitude
- else:
- len_x = region_w * magnitude
- len_y = region_h * magnitude
-
- x0 = int(center_x - len_x * 0.5)
- y0 = int(center_y - len_y * 0.5)
- x1 = int(center_x + len_x * 0.5)
- y1 = int(center_y + len_y * 0.5)
-
- return _Rect(x0, y0, x1, y1)
-
-
-def rect_to_rect2(rect):
- """
- Convert Rect1 to Rect2
- """
-
- return _Rect2(rect.x0, rect.y0, rect.x1 - rect.x0, rect.y1 - rect.y0)
-
-
-def region_to_canvas(rg_vec, canvas):
- """
- Convert screen region to canvas
- """
-
- cv_rect = rect_to_rect2(canvas)
- cv_vec = mathutils.Vector()
- cv_vec.x = (rg_vec.x - cv_rect.x) / cv_rect.width
- cv_vec.y = (rg_vec.y - cv_rect.y) / cv_rect.height
-
- return cv_vec
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
diff --git a/uv_magic_uv/impl/texture_wrap_impl.py b/uv_magic_uv/impl/texture_wrap_impl.py
deleted file mode 100644
index 336b1760..00000000
--- a/uv_magic_uv/impl/texture_wrap_impl.py
+++ /dev/null
@@ -1,236 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-class ReferImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, ops_obj, context):
- props = context.scene.muv_props.texture_wrap
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
-
- sel_faces = [f for f in bm.faces if f.select]
- if len(sel_faces) != 1:
- ops_obj.report({'WARNING'}, "Must select only one face")
- return {'CANCELLED'}
-
- props.ref_face_index = sel_faces[0].index
- props.ref_obj = obj
-
- return {'FINISHED'}
-
-
-class SetImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- sc = context.scene
- props = sc.muv_props.texture_wrap
- if not props.ref_obj:
- return False
- return _is_valid_context(context)
-
- def execute(self, ops_obj, context):
- sc = context.scene
- props = sc.muv_props.texture_wrap
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
-
- if sc.muv_texture_wrap_selseq:
- sel_faces = []
- for hist in bm.select_history:
- if isinstance(hist, bmesh.types.BMFace) and hist.select:
- sel_faces.append(hist)
- if not sel_faces:
- ops_obj.report({'WARNING'}, "Must select more than one face")
- return {'CANCELLED'}
- else:
- sel_faces = [f for f in bm.faces if f.select]
- if len(sel_faces) != 1:
- ops_obj.report({'WARNING'}, "Must select only one face")
- return {'CANCELLED'}
-
- ref_face_index = props.ref_face_index
- for face in sel_faces:
- tgt_face_index = face.index
- if ref_face_index == tgt_face_index:
- ops_obj.report({'WARNING'}, "Must select different face")
- return {'CANCELLED'}
-
- if props.ref_obj != obj:
- ops_obj.report({'WARNING'}, "Object must be same")
- return {'CANCELLED'}
-
- ref_face = bm.faces[ref_face_index]
- tgt_face = bm.faces[tgt_face_index]
-
- # get common vertices info
- common_verts = []
- for sl in ref_face.loops:
- for dl in tgt_face.loops:
- if sl.vert == dl.vert:
- info = {"vert": sl.vert, "ref_loop": sl,
- "tgt_loop": dl}
- common_verts.append(info)
- break
-
- if len(common_verts) != 2:
- ops_obj.report({'WARNING'},
- "2 vertices must be shared among faces")
- return {'CANCELLED'}
-
- # get reference other vertices info
- ref_other_verts = []
- for sl in ref_face.loops:
- for ci in common_verts:
- if sl.vert == ci["vert"]:
- break
- else:
- info = {"vert": sl.vert, "loop": sl}
- ref_other_verts.append(info)
-
- if not ref_other_verts:
- ops_obj.report({'WARNING'},
- "More than 1 vertex must be unshared")
- return {'CANCELLED'}
-
- # get reference info
- ref_info = {}
- cv0 = common_verts[0]["vert"].co
- cv1 = common_verts[1]["vert"].co
- cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
- cuv1 = common_verts[1]["ref_loop"][uv_layer].uv
- ov0 = ref_other_verts[0]["vert"].co
- ouv0 = ref_other_verts[0]["loop"][uv_layer].uv
- ref_info["vert_vdiff"] = cv1 - cv0
- ref_info["uv_vdiff"] = cuv1 - cuv0
- ref_info["vert_hdiff"], _ = common.diff_point_to_segment(
- cv0, cv1, ov0)
- ref_info["uv_hdiff"], _ = common.diff_point_to_segment(
- cuv0, cuv1, ouv0)
-
- # get target other vertices info
- tgt_other_verts = []
- for dl in tgt_face.loops:
- for ci in common_verts:
- if dl.vert == ci["vert"]:
- break
- else:
- info = {"vert": dl.vert, "loop": dl}
- tgt_other_verts.append(info)
-
- if not tgt_other_verts:
- ops_obj.report({'WARNING'},
- "More than 1 vertex must be unshared")
- return {'CANCELLED'}
-
- # get target info
- for info in tgt_other_verts:
- cv0 = common_verts[0]["vert"].co
- cv1 = common_verts[1]["vert"].co
- cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
- ov = info["vert"].co
- info["vert_hdiff"], x = common.diff_point_to_segment(
- cv0, cv1, ov)
- info["vert_vdiff"] = x - common_verts[0]["vert"].co
-
- # calclulate factor
- fact_h = -info["vert_hdiff"].length / \
- ref_info["vert_hdiff"].length
- fact_v = info["vert_vdiff"].length / \
- ref_info["vert_vdiff"].length
- duv_h = ref_info["uv_hdiff"] * fact_h
- duv_v = ref_info["uv_vdiff"] * fact_v
-
- # get target UV
- info["target_uv"] = cuv0 + duv_h + duv_v
-
- # apply to common UVs
- for info in common_verts:
- info["tgt_loop"][uv_layer].uv = \
- info["ref_loop"][uv_layer].uv.copy()
- # apply to other UVs
- for info in tgt_other_verts:
- info["loop"][uv_layer].uv = info["target_uv"]
-
- common.debug_print("===== Target Other Vertices =====")
- common.debug_print(tgt_other_verts)
-
- bmesh.update_edit_mesh(obj.data)
-
- ref_face_index = tgt_face_index
-
- if sc.muv_texture_wrap_set_and_refer:
- props.ref_face_index = tgt_face_index
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/transfer_uv_impl.py b/uv_magic_uv/impl/transfer_uv_impl.py
deleted file mode 100644
index adc97352..00000000
--- a/uv_magic_uv/impl/transfer_uv_impl.py
+++ /dev/null
@@ -1,330 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from collections import OrderedDict
-
-import bpy
-import bmesh
-
-from .. import common
-
-
-__all__ = [
- 'is_valid_context',
- 'get_uv_layer',
- 'main_parse',
- 'parse_faces',
- 'get_new_shared_faces',
- 'get_other_verts_edges',
- 'get_selected_src_faces',
- 'paste_uv',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def get_uv_layer(ops_obj, bm):
- # get UV layer
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'}, "Object must have more than one UV map")
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- return uv_layer
-
-
-def main_parse(ops_obj, uv_layer, sel_faces, active_face, active_face_nor):
- all_sorted_faces = OrderedDict() # This is the main stuff
-
- used_verts = set()
- used_edges = set()
-
- faces_to_parse = []
-
- # get shared edge of two faces
- cross_edges = []
- for edge in active_face.edges:
- if edge in sel_faces[0].edges and edge in sel_faces[1].edges:
- cross_edges.append(edge)
-
- # parse two selected faces
- if cross_edges and len(cross_edges) == 1:
- shared_edge = cross_edges[0]
- vert1 = None
- vert2 = None
-
- dot_n = active_face_nor.normalized()
- edge_vec_1 = (shared_edge.verts[1].co - shared_edge.verts[0].co)
- edge_vec_len = edge_vec_1.length
- edge_vec_1 = edge_vec_1.normalized()
-
- af_center = active_face.calc_center_median()
- af_vec = shared_edge.verts[0].co + (edge_vec_1 * (edge_vec_len * 0.5))
- af_vec = (af_vec - af_center).normalized()
-
- if af_vec.cross(edge_vec_1).dot(dot_n) > 0:
- vert1 = shared_edge.verts[0]
- vert2 = shared_edge.verts[1]
- else:
- vert1 = shared_edge.verts[1]
- vert2 = shared_edge.verts[0]
-
- # get active face stuff and uvs
- face_stuff = get_other_verts_edges(
- active_face, vert1, vert2, shared_edge, uv_layer)
- all_sorted_faces[active_face] = face_stuff
- used_verts.update(active_face.verts)
- used_edges.update(active_face.edges)
-
- # get first selected face stuff and uvs as they share shared_edge
- second_face = sel_faces[0]
- if second_face is active_face:
- second_face = sel_faces[1]
- face_stuff = get_other_verts_edges(
- second_face, vert1, vert2, shared_edge, uv_layer)
- all_sorted_faces[second_face] = face_stuff
- used_verts.update(second_face.verts)
- used_edges.update(second_face.edges)
-
- # first Grow
- faces_to_parse.append(active_face)
- faces_to_parse.append(second_face)
-
- else:
- ops_obj.report({'WARNING'}, "Two faces should share one edge")
- return None
-
- # parse all faces
- while True:
- new_parsed_faces = []
- if not faces_to_parse:
- break
- for face in faces_to_parse:
- face_stuff = all_sorted_faces.get(face)
- new_faces = parse_faces(face, face_stuff, used_verts, used_edges,
- all_sorted_faces, uv_layer)
- if new_faces is None:
- ops_obj.report({'WARNING'}, "More than 2 faces share edge")
- return None
-
- new_parsed_faces += new_faces
- faces_to_parse = new_parsed_faces
-
- return all_sorted_faces
-
-
-def parse_faces(check_face, face_stuff, used_verts, used_edges,
- all_sorted_faces, uv_layer):
- """recurse faces around the new_grow only"""
-
- new_shared_faces = []
- for sorted_edge in face_stuff[1]:
- shared_faces = sorted_edge.link_faces
- if shared_faces:
- if len(shared_faces) > 2:
- bpy.ops.mesh.select_all(action='DESELECT')
- for face_sel in shared_faces:
- face_sel.select = True
- shared_faces = []
- return None
-
- clear_shared_faces = get_new_shared_faces(
- check_face, sorted_edge, shared_faces, all_sorted_faces.keys())
- if clear_shared_faces:
- shared_face = clear_shared_faces[0]
- # get vertices of the edge
- vert1 = sorted_edge.verts[0]
- vert2 = sorted_edge.verts[1]
-
- common.debug_print(face_stuff[0], vert1, vert2)
- if face_stuff[0].index(vert1) > face_stuff[0].index(vert2):
- vert1 = sorted_edge.verts[1]
- vert2 = sorted_edge.verts[0]
-
- common.debug_print(shared_face.verts, vert1, vert2)
- new_face_stuff = get_other_verts_edges(
- shared_face, vert1, vert2, sorted_edge, uv_layer)
- all_sorted_faces[shared_face] = new_face_stuff
- used_verts.update(shared_face.verts)
- used_edges.update(shared_face.edges)
-
- if common.is_debug_mode():
- shared_face.select = True # test which faces are parsed
-
- new_shared_faces.append(shared_face)
-
- return new_shared_faces
-
-
-def get_new_shared_faces(orig_face, shared_edge, check_faces, used_faces):
- shared_faces = []
-
- for face in check_faces:
- is_shared_edge = shared_edge in face.edges
- not_used = face not in used_faces
- not_orig = face is not orig_face
- not_hide = face.hide is False
- if is_shared_edge and not_used and not_orig and not_hide:
- shared_faces.append(face)
-
- return shared_faces
-
-
-def get_other_verts_edges(face, vert1, vert2, first_edge, uv_layer):
- face_edges = [first_edge]
- face_verts = [vert1, vert2]
- face_loops = []
-
- other_edges = [edge for edge in face.edges if edge not in face_edges]
-
- for _ in range(len(other_edges)):
- found_edge = None
- # get sorted verts and edges
- for edge in other_edges:
- if face_verts[-1] in edge.verts:
- other_vert = edge.other_vert(face_verts[-1])
-
- if other_vert not in face_verts:
- face_verts.append(other_vert)
-
- found_edge = edge
- if found_edge not in face_edges:
- face_edges.append(edge)
- break
-
- other_edges.remove(found_edge)
-
- # get sorted uvs
- for vert in face_verts:
- for loop in face.loops:
- if loop.vert is vert:
- face_loops.append(loop[uv_layer])
- break
-
- return [face_verts, face_edges, face_loops]
-
-
-def get_selected_src_faces(ops_obj, bm, uv_layer):
- topology_copied = []
-
- # get selected faces
- active_face = bm.faces.active
- sel_faces = [face for face in bm.faces if face.select]
- if len(sel_faces) != 2:
- ops_obj.report({'WARNING'}, "Two faces must be selected")
- return None
- if not active_face or active_face not in sel_faces:
- ops_obj.report({'WARNING'}, "Two faces must be active")
- return None
-
- # parse all faces according to selection
- active_face_nor = active_face.normal.copy()
- all_sorted_faces = main_parse(ops_obj, uv_layer, sel_faces, active_face,
- active_face_nor)
-
- if all_sorted_faces:
- for face_data in all_sorted_faces.values():
- edges = face_data[1]
- uv_loops = face_data[2]
- uvs = [l.uv.copy() for l in uv_loops]
- pin_uvs = [l.pin_uv for l in uv_loops]
- seams = [e.seam for e in edges]
- topology_copied.append([uvs, pin_uvs, seams])
- else:
- return None
-
- return topology_copied
-
-
-def paste_uv(ops_obj, bm, uv_layer, src_faces, invert_normals, copy_seams):
- # get selection history
- all_sel_faces = [e for e in bm.select_history
- if isinstance(e, bmesh.types.BMFace) and e.select]
- if len(all_sel_faces) % 2 != 0:
- ops_obj.report({'WARNING'}, "Two faces must be selected")
- return -1
-
- # parse selection history
- for i, _ in enumerate(all_sel_faces):
- 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 invert_normals:
- active_face_nor.negate()
- all_sorted_faces = main_parse(ops_obj, 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(src_faces):
- ops_obj.report({'WARNING'},
- "Mesh has different amount of faces")
- return -1
-
- for j, face_data in enumerate(all_sorted_faces.values()):
- copied_data = src_faces[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
- ops_obj.report({'WARNING'},
- "Face have different amount of vertices")
- return 0
-
- 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 copy_seams:
- edge.seam = copied_data[2][k]
- else:
- return -1
-
- return 0
diff --git a/uv_magic_uv/impl/unwrap_constraint_impl.py b/uv_magic_uv/impl/unwrap_constraint_impl.py
deleted file mode 100644
index 25719798..00000000
--- a/uv_magic_uv/impl/unwrap_constraint_impl.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# ##### 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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-
-from .. import common
-
-
-def _is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-class UnwrapConstraintImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- # bpy.ops.uv.unwrap() makes one UV map at least
- if not bm.loops.layers.uv:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
- uv_layer = bm.loops.layers.uv.verify()
-
- # get original UV coordinate
- faces = [f for f in bm.faces if f.select]
- uv_list = []
- for f in faces:
- uvs = [l[uv_layer].uv.copy() for l in f.loops]
- uv_list.append(uvs)
-
- # unwrap
- bpy.ops.uv.unwrap(
- method=ops_obj.method,
- fill_holes=ops_obj.fill_holes,
- correct_aspect=ops_obj.correct_aspect,
- use_subsurf_data=ops_obj.use_subsurf_data,
- margin=ops_obj.margin)
-
- # when U/V-Constraint is checked, revert original coordinate
- for f, uvs in zip(faces, uv_list):
- for l, uv in zip(f.loops, uvs):
- if ops_obj.u_const:
- l[uv_layer].uv.x = uv.x
- if ops_obj.v_const:
- l[uv_layer].uv.y = uv.y
-
- # update mesh
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/impl/uv_bounding_box_impl.py b/uv_magic_uv/impl/uv_bounding_box_impl.py
deleted file mode 100644
index bce51f3e..00000000
--- a/uv_magic_uv/impl/uv_bounding_box_impl.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from enum import IntEnum
-import math
-
-import mathutils
-
-
-MAX_VALUE = 100000.0
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
diff --git a/uv_magic_uv/impl/uv_inspection_impl.py b/uv_magic_uv/impl/uv_inspection_impl.py
deleted file mode 100644
index caa3aa79..00000000
--- a/uv_magic_uv/impl/uv_inspection_impl.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-
-from .. import common
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
- # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
- # after the execution
- for space in context.area.spaces:
- if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
- break
- else:
- return False
-
- return True
-
-
-def update_uvinsp_info(context):
- sc = context.scene
- props = sc.muv_props.uv_inspection
-
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- uv_layer = bm.loops.layers.uv.verify()
-
- if context.tool_settings.use_uv_select_sync:
- sel_faces = [f for f in bm.faces]
- else:
- sel_faces = [f for f in bm.faces if f.select]
- props.overlapped_info = common.get_overlapped_uv_info(
- bm, sel_faces, uv_layer, sc.muv_uv_inspection_show_mode)
- props.flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
diff --git a/uv_magic_uv/impl/uv_sculpt_impl.py b/uv_magic_uv/impl/uv_sculpt_impl.py
deleted file mode 100644
index 284787d8..00000000
--- a/uv_magic_uv/impl/uv_sculpt_impl.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def get_strength(p, len_, factor):
- f = factor
-
- if p > len_:
- return 0.0
-
- if p < 0.0:
- return f
-
- return (len_ - p) * f / len_
diff --git a/uv_magic_uv/impl/uvw_impl.py b/uv_magic_uv/impl/uvw_impl.py
deleted file mode 100644
index 98da0dc9..00000000
--- a/uv_magic_uv/impl/uvw_impl.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-from math import sin, cos, pi
-
-from mathutils import Vector
-
-from .. import common
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def get_uv_layer(ops_obj, bm, assign_uvmap):
- # get UV layer
- if not bm.loops.layers.uv:
- if assign_uvmap:
- bm.loops.layers.uv.new()
- else:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return None
- uv_layer = bm.loops.layers.uv.verify()
-
- return uv_layer
-
-
-def apply_box_map(bm, uv_layer, size, offset, rotation, tex_aspect):
- scale = 1.0 / size
-
- sx = 1.0 * scale
- sy = 1.0 * scale
- sz = 1.0 * scale
- ofx = offset[0]
- ofy = offset[1]
- ofz = offset[2]
- rx = rotation[0] * pi / 180.0
- ry = rotation[1] * pi / 180.0
- rz = rotation[2] * pi / 180.0
- aspect = 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))
-
-
-def apply_planer_map(bm, uv_layer, size, offset, rotation, tex_aspect):
- scale = 1.0 / size
-
- sx = 1.0 * scale
- sy = 1.0 * scale
- ofx = offset[0]
- ofy = offset[1]
- rz = rotation * pi / 180.0
- aspect = 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:
- if common.check_version(2, 80, 0) >= 0:
- # pylint: disable=E0001
- co = q @ l.vert.co
- else:
- 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))
diff --git a/uv_magic_uv/impl/world_scale_uv_impl.py b/uv_magic_uv/impl/world_scale_uv_impl.py
deleted file mode 100644
index 3f376f0d..00000000
--- a/uv_magic_uv/impl/world_scale_uv_impl.py
+++ /dev/null
@@ -1,383 +0,0 @@
-# <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__ = "McBuff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from math import sqrt
-
-import bmesh
-from mathutils import Vector
-
-from .. import common
-
-
-def _is_valid_context(context):
- obj = context.object
-
- # only edit mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'EDIT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-def _measure_wsuv_info(obj, tex_size=None):
- mesh_area = common.measure_mesh_area(obj)
- if common.check_version(2, 80, 0) >= 0:
- uv_area = common.measure_uv_area(obj, tex_size)
- else:
- uv_area = common.measure_uv_area_legacy(obj, tex_size)
-
- if not uv_area:
- return None, mesh_area, None
-
- if mesh_area == 0.0:
- density = 0.0
- else:
- density = sqrt(uv_area) / sqrt(mesh_area)
-
- return uv_area, mesh_area, density
-
-
-def _apply(obj, origin, factor):
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- sel_faces = [f for f in bm.faces if f.select]
-
- uv_layer = bm.loops.layers.uv.verify()
-
- # calculate origin
- if 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 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 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 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 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 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 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 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 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)
-
-
-class MeasureImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def execute(self, ops_obj, context):
- sc = context.scene
- obj = context.active_object
-
- uv_area, mesh_area, density = _measure_wsuv_info(obj)
- if not uv_area:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map and texture")
- return {'CANCELLED'}
-
- sc.muv_world_scale_uv_src_uv_area = uv_area
- sc.muv_world_scale_uv_src_mesh_area = mesh_area
- sc.muv_world_scale_uv_src_density = density
-
- ops_obj.report({'INFO'},
- "UV Area: {0}, Mesh Area: {1}, Texel Density: {2}"
- .format(uv_area, mesh_area, density))
-
- return {'FINISHED'}
-
-
-class ApplyManualImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def __apply_manual(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- tex_size = ops_obj.tgt_texture_size
- uv_area, _, density = _measure_wsuv_info(obj, tex_size)
- if not uv_area:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
-
- tgt_density = ops_obj.tgt_density
- factor = tgt_density / density
-
- _apply(context.active_object, ops_obj.origin, factor)
- ops_obj.report({'INFO'}, "Scaling factor: {0}".format(factor))
-
- return {'FINISHED'}
-
- def draw(self, ops_obj, _):
- layout = ops_obj.layout
-
- layout.prop(ops_obj, "tgt_density")
- layout.prop(ops_obj, "tgt_texture_size")
- layout.prop(ops_obj, "origin")
-
- layout.separator()
-
- def invoke(self, ops_obj, context, _):
- if ops_obj.show_dialog:
- wm = context.window_manager
- return wm.invoke_props_dialog(ops_obj)
-
- return ops_obj.execute(context)
-
- def execute(self, ops_obj, context):
- return self.__apply_manual(ops_obj, context)
-
-
-class ApplyScalingDensityImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def __apply_scaling_density(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- uv_area, _, density = _measure_wsuv_info(obj)
- if not uv_area:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map and texture")
- return {'CANCELLED'}
-
- tgt_density = ops_obj.src_density * ops_obj.tgt_scaling_factor
- factor = tgt_density / density
-
- _apply(context.active_object, ops_obj.origin, factor)
- ops_obj.report({'INFO'}, "Scaling factor: {0}".format(factor))
-
- return {'FINISHED'}
-
- def draw(self, ops_obj, _):
- layout = ops_obj.layout
-
- layout.label(text="Source:")
- col = layout.column()
- col.prop(ops_obj, "src_density")
- col.enabled = False
-
- layout.separator()
-
- if not ops_obj.same_density:
- layout.prop(ops_obj, "tgt_scaling_factor")
- layout.prop(ops_obj, "origin")
-
- layout.separator()
-
- def invoke(self, ops_obj, context, _):
- sc = context.scene
-
- if ops_obj.show_dialog:
- wm = context.window_manager
-
- if ops_obj.same_density:
- ops_obj.tgt_scaling_factor = 1.0
- else:
- ops_obj.tgt_scaling_factor = \
- sc.muv_world_scale_uv_tgt_scaling_factor
- ops_obj.src_density = sc.muv_world_scale_uv_src_density
-
- return wm.invoke_props_dialog(ops_obj)
-
- return ops_obj.execute(context)
-
- def execute(self, ops_obj, context):
- if ops_obj.same_density:
- ops_obj.tgt_scaling_factor = 1.0
-
- return self.__apply_scaling_density(ops_obj, context)
-
-
-class ApplyProportionalToMeshImpl:
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return _is_valid_context(context)
-
- def __apply_proportional_to_mesh(self, ops_obj, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.verts.ensure_lookup_table()
- bm.edges.ensure_lookup_table()
- bm.faces.ensure_lookup_table()
-
- uv_area, mesh_area, density = _measure_wsuv_info(obj)
- if not uv_area:
- ops_obj.report({'WARNING'},
- "Object must have more than one UV map and texture")
- return {'CANCELLED'}
-
- tgt_density = ops_obj.src_density * sqrt(mesh_area) / sqrt(
- ops_obj.src_mesh_area)
-
- factor = tgt_density / density
-
- _apply(context.active_object, ops_obj.origin, factor)
- ops_obj.report({'INFO'}, "Scaling factor: {0}".format(factor))
-
- return {'FINISHED'}
-
- def draw(self, ops_obj, _):
- layout = ops_obj.layout
-
- layout.label(text="Source:")
- col = layout.column(align=True)
- col.prop(ops_obj, "src_density")
- col.prop(ops_obj, "src_uv_area")
- col.prop(ops_obj, "src_mesh_area")
- col.enabled = False
-
- layout.separator()
- layout.prop(ops_obj, "origin")
-
- layout.separator()
-
- def invoke(self, ops_obj, context, _):
- if ops_obj.show_dialog:
- wm = context.window_manager
- sc = context.scene
-
- ops_obj.src_density = sc.muv_world_scale_uv_src_density
- ops_obj.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
-
- return wm.invoke_props_dialog(ops_obj)
-
- return ops_obj.execute(context)
-
- def execute(self, ops_obj, context):
- return self.__apply_proportional_to_mesh(ops_obj, context)
diff --git a/uv_magic_uv/legacy/__init__.py b/uv_magic_uv/legacy/__init__.py
deleted file mode 100644
index 794d02bc..00000000
--- a/uv_magic_uv/legacy/__init__.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
- import importlib
- importlib.reload(op)
- importlib.reload(ui)
- importlib.reload(properites)
- importlib.reload(preferences)
-else:
- from . import op
- from . import ui
- from . import properites
- from . import preferences
-
-import bpy
diff --git a/uv_magic_uv/legacy/op/__init__.py b/uv_magic_uv/legacy/op/__init__.py
deleted file mode 100644
index 9535b76d..00000000
--- a/uv_magic_uv/legacy/op/__init__.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
- import importlib
- importlib.reload(align_uv)
- importlib.reload(align_uv_cursor)
- importlib.reload(copy_paste_uv)
- importlib.reload(copy_paste_uv_object)
- importlib.reload(copy_paste_uv_uvedit)
- importlib.reload(flip_rotate_uv)
- importlib.reload(mirror_uv)
- importlib.reload(move_uv)
- importlib.reload(pack_uv)
- importlib.reload(preserve_uv_aspect)
- importlib.reload(select_uv)
- importlib.reload(smooth_uv)
- importlib.reload(texture_lock)
- importlib.reload(texture_projection)
- importlib.reload(texture_wrap)
- importlib.reload(transfer_uv)
- importlib.reload(unwrap_constraint)
- importlib.reload(uv_bounding_box)
- importlib.reload(uv_inspection)
- importlib.reload(uv_sculpt)
- importlib.reload(uvw)
- importlib.reload(world_scale_uv)
-else:
- from . import align_uv
- from . import align_uv_cursor
- from . import copy_paste_uv
- from . import copy_paste_uv_object
- from . import copy_paste_uv_uvedit
- from . import flip_rotate_uv
- from . import mirror_uv
- from . import move_uv
- from . import pack_uv
- from . import preserve_uv_aspect
- from . import select_uv
- from . import smooth_uv
- from . import texture_lock
- from . import texture_projection
- from . import texture_wrap
- from . import transfer_uv
- from . import unwrap_constraint
- from . import uv_bounding_box
- from . import uv_inspection
- from . import uv_sculpt
- from . import uvw
- from . import world_scale_uv
-
-import bpy
diff --git a/uv_magic_uv/legacy/op/align_uv.py b/uv_magic_uv/legacy/op/align_uv.py
deleted file mode 100644
index a274d583..00000000
--- a/uv_magic_uv/legacy/op/align_uv.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import EnumProperty, BoolProperty, FloatProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import align_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "align_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_align_uv_enabled = BoolProperty(
- name="Align UV Enabled",
- description="Align UV is enabled",
- default=False
- )
- scene.muv_align_uv_transmission = BoolProperty(
- name="Transmission",
- description="Align linked UVs",
- default=False
- )
- scene.muv_align_uv_select = BoolProperty(
- name="Select",
- description="Select UVs which are aligned",
- default=False
- )
- scene.muv_align_uv_vertical = BoolProperty(
- name="Vert-Infl (Vertical)",
- description="Align vertical direction influenced "
- "by mesh vertex proportion",
- default=False
- )
- scene.muv_align_uv_horizontal = BoolProperty(
- name="Vert-Infl (Horizontal)",
- description="Align horizontal direction influenced "
- "by mesh vertex proportion",
- default=False
- )
- scene.muv_align_uv_mesh_infl = FloatProperty(
- name="Mesh Influence",
- description="Influence rate of mesh vertex",
- min=0.0,
- max=1.0,
- default=0.0
- )
- scene.muv_align_uv_location = EnumProperty(
- name="Location",
- description="Align location",
- items=[
- ('LEFT_TOP', "Left/Top", "Align to Left or Top"),
- ('MIDDLE', "Middle", "Align to middle"),
- ('RIGHT_BOTTOM', "Right/Bottom", "Align to Right or Bottom")
- ],
- default='MIDDLE'
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_align_uv_enabled
- del scene.muv_align_uv_transmission
- del scene.muv_align_uv_select
- del scene.muv_align_uv_vertical
- del scene.muv_align_uv_horizontal
- del scene.muv_align_uv_mesh_infl
- del scene.muv_align_uv_location
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUV_Circle(bpy.types.Operator):
-
- bl_idname = "uv.muv_align_uv_operator_circle"
- bl_label = "Align UV (Circle)"
- bl_description = "Align UV coordinates to Circle"
- bl_options = {'REGISTER', 'UNDO'}
-
- transmission = BoolProperty(
- name="Transmission",
- description="Align linked UVs",
- default=False
- )
- select = BoolProperty(
- name="Select",
- description="Select UVs which are aligned",
- default=False
- )
-
- def __init__(self):
- self.__impl = impl.CircleImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.CircleImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
-
- bl_idname = "uv.muv_align_uv_operator_straighten"
- bl_label = "Align UV (Straighten)"
- bl_description = "Straighten UV coordinates"
- bl_options = {'REGISTER', 'UNDO'}
-
- transmission = BoolProperty(
- name="Transmission",
- description="Align linked UVs",
- default=False
- )
- select = BoolProperty(
- name="Select",
- description="Select UVs which are aligned",
- default=False
- )
- vertical = BoolProperty(
- name="Vert-Infl (Vertical)",
- description="Align vertical direction influenced "
- "by mesh vertex proportion",
- default=False
- )
- horizontal = BoolProperty(
- name="Vert-Infl (Horizontal)",
- description="Align horizontal direction influenced "
- "by mesh vertex proportion",
- default=False
- )
- mesh_infl = FloatProperty(
- name="Mesh Influence",
- description="Influence rate of mesh vertex",
- min=0.0,
- max=1.0,
- default=0.0
- )
-
- def __init__(self):
- self.__impl = impl.StraightenImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.StraightenImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUV_Axis(bpy.types.Operator):
-
- bl_idname = "uv.muv_align_uv_operator_axis"
- bl_label = "Align UV (XY-Axis)"
- bl_description = "Align UV to XY-axis"
- bl_options = {'REGISTER', 'UNDO'}
-
- transmission = BoolProperty(
- name="Transmission",
- description="Align linked UVs",
- default=False
- )
- select = BoolProperty(
- name="Select",
- description="Select UVs which are aligned",
- default=False
- )
- vertical = BoolProperty(
- name="Vert-Infl (Vertical)",
- description="Align vertical direction influenced "
- "by mesh vertex proportion",
- default=False
- )
- horizontal = BoolProperty(
- name="Vert-Infl (Horizontal)",
- description="Align horizontal direction influenced "
- "by mesh vertex proportion",
- default=False
- )
- location = EnumProperty(
- name="Location",
- description="Align location",
- items=[
- ('LEFT_TOP', "Left/Top", "Align to Left or Top"),
- ('MIDDLE', "Middle", "Align to middle"),
- ('RIGHT_BOTTOM', "Right/Bottom", "Align to Right or Bottom")
- ],
- default='MIDDLE'
- )
- mesh_infl = FloatProperty(
- name="Mesh Influence",
- description="Influence rate of mesh vertex",
- min=0.0,
- max=1.0,
- default=0.0
- )
-
- def __init__(self):
- self.__impl = impl.AxisImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.AxisImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/align_uv_cursor.py b/uv_magic_uv/legacy/op/align_uv_cursor.py
deleted file mode 100644
index 6a08de0b..00000000
--- a/uv_magic_uv/legacy/op/align_uv_cursor.py
+++ /dev/null
@@ -1,153 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from mathutils import Vector
-from bpy.props import EnumProperty, BoolProperty, FloatVectorProperty
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import align_uv_cursor_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "align_uv_cursor"
-
- @classmethod
- def init_props(cls, scene):
- def auvc_get_cursor_loc(self):
- area, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
- 'IMAGE_EDITOR')
- bd_size = common.get_uvimg_editor_board_size(area)
- loc = space.cursor_location
- if bd_size[0] < 0.000001:
- cx = 0.0
- else:
- cx = loc[0] / bd_size[0]
- if bd_size[1] < 0.000001:
- cy = 0.0
- else:
- cy = loc[1] / bd_size[1]
- self['muv_align_uv_cursor_cursor_loc'] = Vector((cx, cy))
- return self.get('muv_align_uv_cursor_cursor_loc', (0.0, 0.0))
-
- def auvc_set_cursor_loc(self, value):
- self['muv_align_uv_cursor_cursor_loc'] = value
- area, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
- 'IMAGE_EDITOR')
- bd_size = common.get_uvimg_editor_board_size(area)
- cx = bd_size[0] * value[0]
- cy = bd_size[1] * value[1]
- space.cursor_location = Vector((cx, cy))
-
- scene.muv_align_uv_cursor_enabled = BoolProperty(
- name="Align UV Cursor Enabled",
- description="Align UV Cursor is enabled",
- default=False
- )
-
- scene.muv_align_uv_cursor_cursor_loc = FloatVectorProperty(
- name="UV Cursor Location",
- size=2,
- precision=4,
- soft_min=-1.0,
- soft_max=1.0,
- step=1,
- default=(0.000, 0.000),
- get=auvc_get_cursor_loc,
- set=auvc_set_cursor_loc
- )
- scene.muv_align_uv_cursor_align_method = EnumProperty(
- name="Align Method",
- description="Align Method",
- default='TEXTURE',
- items=[
- ('TEXTURE', "Texture", "Align to texture"),
- ('UV', "UV", "Align to UV"),
- ('UV_SEL', "UV (Selected)", "Align to Selected UV")
- ]
- )
-
- scene.muv_uv_cursor_location_enabled = BoolProperty(
- name="UV Cursor Location Enabled",
- description="UV Cursor Location is enabled",
- default=False
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_align_uv_cursor_enabled
- del scene.muv_align_uv_cursor_cursor_loc
- del scene.muv_align_uv_cursor_align_method
-
- del scene.muv_uv_cursor_location_enabled
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_AlignUVCursor(bpy.types.Operator):
-
- bl_idname = "uv.muv_align_uv_cursor_operator"
- bl_label = "Align UV Cursor"
- bl_description = "Align cursor to the center of UV island"
- bl_options = {'REGISTER', 'UNDO'}
-
- position = EnumProperty(
- items=(
- ('CENTER', "Center", "Align to Center"),
- ('LEFT_TOP', "Left Top", "Align to Left Top"),
- ('LEFT_MIDDLE', "Left Middle", "Align to Left Middle"),
- ('LEFT_BOTTOM', "Left Bottom", "Align to Left Bottom"),
- ('MIDDLE_TOP', "Middle Top", "Align to Middle Top"),
- ('MIDDLE_BOTTOM', "Middle Bottom", "Align to Middle Bottom"),
- ('RIGHT_TOP', "Right Top", "Align to Right Top"),
- ('RIGHT_MIDDLE', "Right Middle", "Align to Right Middle"),
- ('RIGHT_BOTTOM', "Right Bottom", "Align to Right Bottom")
- ),
- name="Position",
- description="Align position",
- default='CENTER'
- )
- base = EnumProperty(
- items=(
- ('TEXTURE', "Texture", "Align based on Texture"),
- ('UV', "UV", "Align to UV"),
- ('UV_SEL', "UV (Selected)", "Align to Selected UV")
- ),
- name="Base",
- description="Align base",
- default='TEXTURE'
- )
-
- def __init__(self):
- self.__impl = impl.AlignUVCursorLegacyImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.AlignUVCursorLegacyImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/copy_paste_uv.py b/uv_magic_uv/legacy/op/copy_paste_uv.py
deleted file mode 100644
index a8aef017..00000000
--- a/uv_magic_uv/legacy/op/copy_paste_uv.py
+++ /dev/null
@@ -1,531 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>, Jace Priester"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-import bmesh
-import bpy.utils
-from bpy.props import (
- StringProperty,
- BoolProperty,
- IntProperty,
- EnumProperty,
-)
-
-from ...impl import copy_paste_uv_impl as impl
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
- 'Properties',
- 'MUV_OT_CopyPasteUV_CopyUV',
- 'MUV_MT_CopyPasteUV_CopyUV',
- 'MUV_OT_CopyPasteUV_PasteUV',
- 'MUV_MT_CopyPasteUV_PasteUV',
- 'MUV_OT_CopyPasteUV_SelSeqCopyUV',
- 'MUV_MT_CopyPasteUV_SelSeqCopyUV',
- 'MUV_OT_CopyPasteUV_SelSeqPasteUV',
- 'MUV_MT_CopyPasteUV_SelSeqPasteUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "copy_paste_uv"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- src_info = None
-
- scene.muv_props.copy_paste_uv = Props()
- scene.muv_props.copy_paste_uv_selseq = Props()
-
- scene.muv_copy_paste_uv_enabled = BoolProperty(
- name="Copy/Paste UV Enabled",
- description="Copy/Paste UV is enabled",
- default=False
- )
- scene.muv_copy_paste_uv_copy_seams = BoolProperty(
- name="Seams",
- description="Copy Seams",
- default=True
- )
- scene.muv_copy_paste_uv_mode = EnumProperty(
- items=[
- ('DEFAULT', "Default", "Default Mode"),
- ('SEL_SEQ', "Selection Sequence", "Selection Sequence Mode")
- ],
- name="Copy/Paste UV Mode",
- description="Copy/Paste UV Mode",
- default='DEFAULT'
- )
- scene.muv_copy_paste_uv_strategy = EnumProperty(
- name="Strategy",
- description="Paste Strategy",
- items=[
- ('N_N', 'N:N', 'Number of faces must be equal to source'),
- ('N_M', 'N:M', 'Number of faces must not be equal to source')
- ],
- default='N_M'
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_props.copy_paste_uv
- del scene.muv_props.copy_paste_uv_selseq
- del scene.muv_copy_paste_uv_enabled
- del scene.muv_copy_paste_uv_copy_seams
- del scene.muv_copy_paste_uv_mode
- del scene.muv_copy_paste_uv_strategy
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
- """
- Operation class: Copy UV coordinate
- """
-
- bl_idname = "uv.muv_copy_paste_uv_operator_copy_uv"
- bl_label = "Copy UV"
- bl_description = "Copy UV coordinate"
- bl_options = {'REGISTER', 'UNDO'}
-
- uv_map = StringProperty(default="__default", options={'HIDDEN'})
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return impl.is_valid_context(context)
-
- def execute(self, context):
- props = context.scene.muv_props.copy_paste_uv
- obj = context.active_object
- bm = common.create_bmesh(obj)
-
- # get UV layer
- uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
- if not uv_layers:
- return {'CANCELLED'}
-
- # get selected face
- src_info = impl.get_src_face_info(self, bm, uv_layers, True)
- if src_info is None:
- return {'CANCELLED'}
- props.src_info = src_info
-
- face_count = len(props.src_info[list(props.src_info.keys())[0]])
- self.report({'INFO'}, "{} face(s) are copied".format(face_count))
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_CopyUV(bpy.types.Menu):
- """
- Menu class: Copy UV coordinate
- """
-
- bl_idname = "uv.muv_copy_paste_uv_menu_copy_uv"
- bl_label = "Copy UV (Menu)"
- bl_description = "Menu of Copy UV coordinate"
-
- @classmethod
- def poll(cls, context):
- return impl.is_valid_context(context)
-
- def draw(self, context):
- layout = self.layout
- # create sub menu
- obj = context.active_object
- bm = common.create_bmesh(obj)
- uv_maps = bm.loops.layers.uv.keys()
-
- ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname,
- text="[Default]")
- ops.uv_map = "__default"
-
- ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname,
- text="[All]")
- ops.uv_map = "__all"
-
- for m in uv_maps:
- ops = layout.operator(MUV_OT_CopyPasteUV_CopyUV.bl_idname, text=m)
- ops.uv_map = m
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
- """
- Operation class: Paste UV coordinate
- """
-
- bl_idname = "uv.muv_copy_paste_uv_operator_paste_uv"
- bl_label = "Paste UV"
- bl_description = "Paste UV coordinate"
- bl_options = {'REGISTER', 'UNDO'}
-
- uv_map = StringProperty(default="__default", options={'HIDDEN'})
- strategy = EnumProperty(
- name="Strategy",
- description="Paste Strategy",
- items=[
- ('N_N', 'N:N', 'Number of faces must be equal to source'),
- ('N_M', 'N:M', 'Number of faces must not be equal to source')
- ],
- default="N_M"
- )
- flip_copied_uv = BoolProperty(
- name="Flip Copied UV",
- description="Flip Copied UV...",
- default=False
- )
- rotate_copied_uv = IntProperty(
- default=0,
- name="Rotate Copied UV",
- min=0,
- max=30
- )
- copy_seams = BoolProperty(
- name="Seams",
- description="Copy Seams",
- default=True
- )
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- sc = context.scene
- props = sc.muv_props.copy_paste_uv
- if not props.src_info:
- return False
- return impl.is_valid_context(context)
-
- def execute(self, context):
- props = context.scene.muv_props.copy_paste_uv
- if not props.src_info:
- self.report({'WARNING'}, "Need copy UV at first")
- return {'CANCELLED'}
- obj = context.active_object
- bm = common.create_bmesh(obj)
-
- # get UV layer
- uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
- self.uv_map)
- if not uv_layers:
- return {'CANCELLED'}
-
- # get selected face
- dest_info = impl.get_dest_face_info(self, bm, uv_layers,
- props.src_info, self.strategy,
- True)
- if dest_info is None:
- return {'CANCELLED'}
-
- # paste
- ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
- self.strategy, self.flip_copied_uv,
- self.rotate_copied_uv, self.copy_seams)
- if ret:
- return {'CANCELLED'}
-
- face_count = len(props.src_info[list(dest_info.keys())[0]])
- self.report({'INFO'}, "{} face(s) are pasted".format(face_count))
-
- bmesh.update_edit_mesh(obj.data)
- if self.copy_seams is True:
- obj.data.show_edge_seams = True
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_PasteUV(bpy.types.Menu):
- """
- Menu class: Paste UV coordinate
- """
-
- bl_idname = "uv.muv_copy_paste_uv_menu_paste_uv"
- bl_label = "Paste UV (Menu)"
- bl_description = "Menu of Paste UV coordinate"
-
- @classmethod
- def poll(cls, context):
- sc = context.scene
- props = sc.muv_props.copy_paste_uv
- if not props.src_info:
- return False
- return impl.is_valid_context(context)
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
- # create sub menu
- obj = context.active_object
- bm = common.create_bmesh(obj)
- uv_maps = bm.loops.layers.uv.keys()
-
- ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
- text="[Default]")
- ops.uv_map = "__default"
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
-
- ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
- text="[New]")
- ops.uv_map = "__new"
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
-
- ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname,
- text="[All]")
- ops.uv_map = "__all"
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
-
- for m in uv_maps:
- ops = layout.operator(MUV_OT_CopyPasteUV_PasteUV.bl_idname, text=m)
- ops.uv_map = m
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
- """
- Operation class: Copy UV coordinate by selection sequence
- """
-
- bl_idname = "uv.muv_copy_paste_uv_operator_selseq_copy_uv"
- bl_label = "Copy UV (Selection Sequence)"
- bl_description = "Copy UV data by selection sequence"
- bl_options = {'REGISTER', 'UNDO'}
-
- uv_map = StringProperty(default="__default", options={'HIDDEN'})
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return impl.is_valid_context(context)
-
- def execute(self, context):
- props = context.scene.muv_props.copy_paste_uv_selseq
- obj = context.active_object
- bm = common.create_bmesh(obj)
-
- # get UV layer
- uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
- if not uv_layers:
- return {'CANCELLED'}
-
- # get selected face
- src_info = impl.get_select_history_src_face_info(self, bm, uv_layers)
- if src_info is None:
- return {'CANCELLED'}
- props.src_info = src_info
-
- face_count = len(props.src_info[list(props.src_info.keys())[0]])
- self.report({'INFO'}, "{} face(s) are selected".format(face_count))
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_SelSeqCopyUV(bpy.types.Menu):
- """
- Menu class: Copy UV coordinate by selection sequence
- """
-
- bl_idname = "uv.muv_copy_paste_uv_menu_selseq_copy_uv"
- bl_label = "Copy UV (Selection Sequence) (Menu)"
- bl_description = "Menu of Copy UV coordinate by selection sequence"
-
- @classmethod
- def poll(cls, context):
- return impl.is_valid_context(context)
-
- def draw(self, context):
- layout = self.layout
- obj = context.active_object
- bm = common.create_bmesh(obj)
- uv_maps = bm.loops.layers.uv.keys()
-
- ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
- text="[Default]")
- ops.uv_map = "__default"
-
- ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
- text="[All]")
- ops.uv_map = "__all"
-
- for m in uv_maps:
- ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqCopyUV.bl_idname,
- text=m)
- ops.uv_map = m
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
- """
- Operation class: Paste UV coordinate by selection sequence
- """
-
- bl_idname = "uv.muv_copy_paste_uv_operator_selseq_paste_uv"
- bl_label = "Paste UV (Selection Sequence)"
- bl_description = "Paste UV coordinate by selection sequence"
- bl_options = {'REGISTER', 'UNDO'}
-
- uv_map = StringProperty(default="__default", options={'HIDDEN'})
- strategy = EnumProperty(
- name="Strategy",
- description="Paste Strategy",
- items=[
- ('N_N', 'N:N', 'Number of faces must be equal to source'),
- ('N_M', 'N:M', 'Number of faces must not be equal to source')
- ],
- default="N_M"
- )
- flip_copied_uv = BoolProperty(
- name="Flip Copied UV",
- description="Flip Copied UV...",
- default=False
- )
- rotate_copied_uv = IntProperty(
- default=0,
- name="Rotate Copied UV",
- min=0,
- max=30
- )
- copy_seams = BoolProperty(
- name="Seams",
- description="Copy Seams",
- default=True
- )
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- sc = context.scene
- props = sc.muv_props.copy_paste_uv_selseq
- if not props.src_info:
- return False
- return impl.is_valid_context(context)
-
- def execute(self, context):
- props = context.scene.muv_props.copy_paste_uv_selseq
- if not props.src_info:
- self.report({'WARNING'}, "Need copy UV at first")
- return {'CANCELLED'}
- obj = context.active_object
- bm = common.create_bmesh(obj)
-
- # get UV layer
- uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
- self.uv_map)
- if not uv_layers:
- return {'CANCELLED'}
-
- # get selected face
- dest_info = impl.get_select_history_dest_face_info(self, bm, uv_layers,
- props.src_info,
- self.strategy)
- if dest_info is None:
- return {'CANCELLED'}
-
- # paste
- ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
- self.strategy, self.flip_copied_uv,
- self.rotate_copied_uv, self.copy_seams)
- if ret:
- return {'CANCELLED'}
-
- face_count = len(props.src_info[list(dest_info.keys())[0]])
- self.report({'INFO'}, "{} face(s) are pasted".format(face_count))
-
- bmesh.update_edit_mesh(obj.data)
- if self.copy_seams is True:
- obj.data.show_edge_seams = True
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_SelSeqPasteUV(bpy.types.Menu):
- """
- Menu class: Paste UV coordinate by selection sequence
- """
-
- bl_idname = "uv.muv_copy_paste_uv_menu_selseq_paste_uv"
- bl_label = "Paste UV (Selection Sequence) (Menu)"
- bl_description = "Menu of Paste UV coordinate by selection sequence"
-
- @classmethod
- def poll(cls, context):
- sc = context.scene
- props = sc.muv_props.copy_paste_uv_selseq
- if not props.src_uvs or not props.src_pin_uvs:
- return False
- return impl.is_valid_context(context)
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
- # create sub menu
- obj = context.active_object
- bm = common.create_bmesh(obj)
- uv_maps = bm.loops.layers.uv.keys()
-
- ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
- text="[Default]")
- ops.uv_map = "__default"
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
-
- ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
- text="[New]")
- ops.uv_map = "__new"
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
-
- ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
- text="[All]")
- ops.uv_map = "__all"
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
-
- for m in uv_maps:
- ops = layout.operator(MUV_OT_CopyPasteUV_SelSeqPasteUV.bl_idname,
- text=m)
- ops.uv_map = m
- ops.copy_seams = sc.muv_copy_paste_uv_copy_seams
- ops.strategy = sc.muv_copy_paste_uv_strategy
diff --git a/uv_magic_uv/legacy/op/copy_paste_uv_object.py b/uv_magic_uv/legacy/op/copy_paste_uv_object.py
deleted file mode 100644
index e09b003b..00000000
--- a/uv_magic_uv/legacy/op/copy_paste_uv_object.py
+++ /dev/null
@@ -1,298 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bmesh
-import bpy
-from bpy.props import (
- StringProperty,
- BoolProperty,
-)
-
-from ...impl import copy_paste_uv_impl as impl
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
- 'Properties',
- 'MUV_OT_CopyPasteUVObject_CopyUV',
- 'MUV_MT_CopyPasteUVObject_CopyUV',
- 'MUV_OT_CopyPasteUVObject_PasteUV',
- 'MUV_MT_CopyPasteUVObject_PasteUV',
-]
-
-
-def is_valid_context(context):
- obj = context.object
-
- # only object mode is allowed to execute
- if obj is None:
- return False
- if obj.type != 'MESH':
- return False
- if context.object.mode != 'OBJECT':
- return False
-
- # only 'VIEW_3D' space is allowed to execute
- for space in context.area.spaces:
- if space.type == 'VIEW_3D':
- break
- else:
- return False
-
- return True
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "copy_paste_uv_object"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- src_info = None
-
- scene.muv_props.copy_paste_uv_object = Props()
-
- scene.muv_copy_paste_uv_object_copy_seams = BoolProperty(
- name="Seams",
- description="Copy Seams",
- default=True
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_props.copy_paste_uv_object
- del scene.muv_copy_paste_uv_object_copy_seams
-
-
-def memorize_view_3d_mode(fn):
- def __memorize_view_3d_mode(self, context):
- mode_orig = bpy.context.object.mode
- result = fn(self, context)
- bpy.ops.object.mode_set(mode=mode_orig)
- return result
- return __memorize_view_3d_mode
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
- """
- Operation class: Copy UV coordinate among objects
- """
-
- bl_idname = "object.muv_copy_paste_uv_object_operator_copy_uv"
- bl_label = "Copy UV (Among Objects)"
- bl_description = "Copy UV coordinate (Among Objects)"
- bl_options = {'REGISTER', 'UNDO'}
-
- uv_map = StringProperty(default="__default", options={'HIDDEN'})
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return is_valid_context(context)
-
- @memorize_view_3d_mode
- def execute(self, context):
- props = context.scene.muv_props.copy_paste_uv_object
- bpy.ops.object.mode_set(mode='EDIT')
- obj = context.active_object
- bm = common.create_bmesh(obj)
-
- # get UV layer
- uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
- if not uv_layers:
- return {'CANCELLED'}
-
- # get selected face
- src_info = impl.get_src_face_info(self, bm, uv_layers)
- if src_info is None:
- return {'CANCELLED'}
- props.src_info = src_info
-
- self.report({'INFO'},
- "{}'s UV coordinates are copied".format(obj.name))
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUVObject_CopyUV(bpy.types.Menu):
- """
- Menu class: Copy UV coordinate among objects
- """
-
- bl_idname = "object.muv_copy_paste_uv_object_menu_copy_uv"
- bl_label = "Copy UV (Among Objects) (Menu)"
- bl_description = "Menu of Copy UV coordinate (Among Objects)"
-
- @classmethod
- def poll(cls, context):
- return is_valid_context(context)
-
- def draw(self, _):
- layout = self.layout
- # create sub menu
- uv_maps = bpy.context.active_object.data.uv_textures.keys()
-
- ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
- text="[Default]")
- ops.uv_map = "__default"
-
- ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
- text="[All]")
- ops.uv_map = "__all"
-
- for m in uv_maps:
- ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
- text=m)
- ops.uv_map = m
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
- """
- Operation class: Paste UV coordinate among objects
- """
-
- bl_idname = "object.muv_copy_paste_uv_object_operator_paste_uv"
- bl_label = "Paste UV (Among Objects)"
- bl_description = "Paste UV coordinate (Among Objects)"
- bl_options = {'REGISTER', 'UNDO'}
-
- uv_map = StringProperty(default="__default", options={'HIDDEN'})
- copy_seams = BoolProperty(
- name="Seams",
- description="Copy Seams",
- default=True
- )
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- sc = context.scene
- props = sc.muv_props.copy_paste_uv_object
- if not props.src_info:
- return False
- return is_valid_context(context)
-
- @memorize_view_3d_mode
- def execute(self, context):
- props = context.scene.muv_props.copy_paste_uv_object
- if not props.src_info:
- self.report({'WARNING'}, "Need copy UV at first")
- return {'CANCELLED'}
-
- for o in bpy.data.objects:
- if not hasattr(o.data, "uv_textures") or not o.select:
- continue
-
- bpy.ops.object.mode_set(mode='OBJECT')
- bpy.context.scene.objects.active = o
- bpy.ops.object.mode_set(mode='EDIT')
-
- obj = context.active_object
- bm = common.create_bmesh(obj)
-
- # get UV layer
- uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
- self.uv_map)
- if not uv_layers:
- return {'CANCELLED'}
-
- # get selected face
- dest_info = impl.get_dest_face_info(self, bm, uv_layers,
- props.src_info, 'N_N')
- if dest_info is None:
- return {'CANCELLED'}
-
- # paste
- ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
- 'N_N', 0, 0, self.copy_seams)
- if ret:
- return {'CANCELLED'}
-
- bmesh.update_edit_mesh(obj.data)
- if self.copy_seams is True:
- obj.data.show_edge_seams = True
-
- self.report(
- {'INFO'}, "{}'s UV coordinates are pasted".format(obj.name))
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUVObject_PasteUV(bpy.types.Menu):
- """
- Menu class: Paste UV coordinate among objects
- """
-
- bl_idname = "object.muv_copy_paste_uv_object_menu_paste_uv"
- bl_label = "Paste UV (Among Objects) (Menu)"
- bl_description = "Menu of Paste UV coordinate (Among Objects)"
-
- @classmethod
- def poll(cls, context):
- sc = context.scene
- props = sc.muv_props.copy_paste_uv_object
- if not props.src_info:
- return False
- return is_valid_context(context)
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
- # create sub menu
- uv_maps = []
- for obj in bpy.data.objects:
- if hasattr(obj.data, "uv_textures") and obj.select:
- uv_maps.extend(obj.data.uv_textures.keys())
-
- ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
- text="[Default]")
- ops.uv_map = "__default"
- ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
-
- ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
- text="[New]")
- ops.uv_map = "__new"
- ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
-
- ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
- text="[All]")
- ops.uv_map = "__all"
- ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
-
- for m in uv_maps:
- ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
- text=m)
- ops.uv_map = m
- ops.copy_seams = sc.muv_copy_paste_uv_object_copy_seams
diff --git a/uv_magic_uv/legacy/op/copy_paste_uv_uvedit.py b/uv_magic_uv/legacy/op/copy_paste_uv_uvedit.py
deleted file mode 100644
index bb72d42a..00000000
--- a/uv_magic_uv/legacy/op/copy_paste_uv_uvedit.py
+++ /dev/null
@@ -1,97 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import copy_paste_uv_uvedit_impl as impl
-
-
-__all__ = [
- 'Properties',
- 'MUV_OT_CopyPasteUVUVEdit_CopyUV',
- 'MUV_OT_CopyPasteUVUVEdit_PasteUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "copy_paste_uv_uvedit"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- src_uvs = None
-
- scene.muv_props.copy_paste_uv_uvedit = Props()
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_props.copy_paste_uv_uvedit
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVUVEdit_CopyUV(bpy.types.Operator):
- """
- Operation class: Copy UV coordinate on UV/Image Editor
- """
-
- bl_idname = "uv.muv_copy_paste_uv_uvedit_operator_copy_uv"
- bl_label = "Copy UV (UV/Image Editor)"
- bl_description = "Copy UV coordinate (only selected in UV/Image Editor)"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.CopyUVImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.CopyUVImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CopyPasteUVUVEdit_PasteUV(bpy.types.Operator):
- """
- Operation class: Paste UV coordinate on UV/Image Editor
- """
-
- bl_idname = "uv.muv_copy_paste_uv_uvedit_operator_paste_uv"
- bl_label = "Paste UV (UV/Image Editor)"
- bl_description = "Paste UV coordinate (only selected in UV/Image Editor)"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.PasteUVImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.PasteUVImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/flip_rotate_uv.py b/uv_magic_uv/legacy/op/flip_rotate_uv.py
deleted file mode 100644
index d94e4808..00000000
--- a/uv_magic_uv/legacy/op/flip_rotate_uv.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from bpy.props import (
- BoolProperty,
- IntProperty,
-)
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import flip_rotate_impl as impl
-
-__all__ = [
- 'Properties',
- 'MUV_OT_FlipRotate',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "flip_rotate_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_flip_rotate_uv_enabled = BoolProperty(
- name="Flip/Rotate UV Enabled",
- description="Flip/Rotate UV is enabled",
- default=False
- )
- scene.muv_flip_rotate_uv_seams = BoolProperty(
- name="Seams",
- description="Seams",
- default=True
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_flip_rotate_uv_enabled
- del scene.muv_flip_rotate_uv_seams
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_FlipRotate(bpy.types.Operator):
- """
- Operation class: Flip and Rotate UV coordinate
- """
-
- bl_idname = "uv.muv_flip_rotate_uv_operator"
- bl_label = "Flip/Rotate UV"
- bl_description = "Flip/Rotate UV coordinate"
- bl_options = {'REGISTER', 'UNDO'}
-
- flip = BoolProperty(
- name="Flip UV",
- description="Flip UV...",
- default=False
- )
- rotate = IntProperty(
- default=0,
- name="Rotate UV",
- min=0,
- max=30
- )
- seams = BoolProperty(
- name="Seams",
- description="Seams",
- default=True
- )
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return impl.is_valid_context(context)
-
- def execute(self, context):
- self.report({'INFO'}, "Flip/Rotate UV")
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- # get UV layer
- uv_layer = impl.get_uv_layer(self, bm)
- if not uv_layer:
- return {'CANCELLED'}
-
- # get selected face
- src_info = impl.get_src_face_info(self, bm, [uv_layer], True)
- if not src_info:
- return {'CANCELLED'}
-
- face_count = len(src_info[list(src_info.keys())[0]])
- self.report({'INFO'}, "{} face(s) are selected".format(face_count))
-
- # paste
- ret = impl.paste_uv(self, bm, src_info, src_info, [uv_layer], 'N_N',
- self.flip, self.rotate, self.seams)
- if ret:
- return {'CANCELLED'}
-
- bmesh.update_edit_mesh(obj.data)
- if self.seams is True:
- obj.data.show_edge_seams = True
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/mirror_uv.py b/uv_magic_uv/legacy/op/mirror_uv.py
deleted file mode 100644
index e869e5e8..00000000
--- a/uv_magic_uv/legacy/op/mirror_uv.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# <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__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
- EnumProperty,
- FloatProperty,
- BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import mirror_uv_impl as impl
-
-
-__all__ = [
- 'Properties',
- 'MUV_OT_MirrorUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "mirror_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_mirror_uv_enabled = BoolProperty(
- name="Mirror UV Enabled",
- description="Mirror UV is enabled",
- default=False
- )
- scene.muv_mirror_uv_axis = EnumProperty(
- items=[
- ('X', "X", "Mirror Along X axis"),
- ('Y', "Y", "Mirror Along Y axis"),
- ('Z', "Z", "Mirror Along Z axis")
- ],
- name="Axis",
- description="Mirror Axis",
- default='X'
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_mirror_uv_enabled
- del scene.muv_mirror_uv_axis
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_MirrorUV(bpy.types.Operator):
- """
- Operation class: Mirror UV
- """
-
- bl_idname = "uv.muv_mirror_uv_operator"
- bl_label = "Mirror UV"
- bl_options = {'REGISTER', 'UNDO'}
-
- axis = EnumProperty(
- items=(
- ('X', "X", "Mirror Along X axis"),
- ('Y', "Y", "Mirror Along Y axis"),
- ('Z', "Z", "Mirror Along Z axis")
- ),
- name="Axis",
- description="Mirror Axis",
- default='X'
- )
- error = FloatProperty(
- name="Error",
- description="Error threshold",
- default=0.001,
- min=0.0,
- max=100.0,
- soft_min=0.0,
- soft_max=1.0
- )
-
- def __init__(self):
- self.__impl = impl.MirrorUVImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.MirrorUVImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/move_uv.py b/uv_magic_uv/legacy/op/move_uv.py
deleted file mode 100644
index 2988c2ce..00000000
--- a/uv_magic_uv/legacy/op/move_uv.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# <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__ = "kgeogeo, mem, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty
-
-from ...impl import move_uv_impl as impl
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
- 'Properties',
- 'MUV_OT_MoveUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "move_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_move_uv_enabled = BoolProperty(
- name="Move UV Enabled",
- description="Move UV is enabled",
- default=False
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_move_uv_enabled
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_MoveUV(bpy.types.Operator):
- """
- Operator class: Move UV
- """
-
- bl_idname = "uv.muv_move_uv_operator"
- bl_label = "Move UV"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.MoveUVImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.MoveUVImpl.poll(context)
-
- @classmethod
- def is_running(cls, _):
- return impl.MoveUVImpl.is_running(_)
-
- def modal(self, context, event):
- return self.__impl.modal(self, context, event)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/pack_uv.py b/uv_magic_uv/legacy/op/pack_uv.py
deleted file mode 100644
index f2e1a190..00000000
--- a/uv_magic_uv/legacy/op/pack_uv.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
- FloatProperty,
- FloatVectorProperty,
- BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import pack_uv_impl as impl
-
-
-__all__ = [
- 'Properties',
- 'MUV_OT_PackUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "pack_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_pack_uv_enabled = BoolProperty(
- name="Pack UV Enabled",
- description="Pack UV is enabled",
- default=False
- )
- scene.muv_pack_uv_allowable_center_deviation = FloatVectorProperty(
- name="Allowable Center Deviation",
- description="Allowable center deviation to judge same UV island",
- min=0.000001,
- max=0.1,
- default=(0.001, 0.001),
- size=2
- )
- scene.muv_pack_uv_allowable_size_deviation = FloatVectorProperty(
- name="Allowable Size Deviation",
- description="Allowable sizse deviation to judge same UV island",
- min=0.000001,
- max=0.1,
- default=(0.001, 0.001),
- size=2
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_pack_uv_enabled
- del scene.muv_pack_uv_allowable_center_deviation
- del scene.muv_pack_uv_allowable_size_deviation
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_PackUV(bpy.types.Operator):
- """
- Operation class: Pack UV with same UV islands are integrated
- Island matching algorithm
- - Same center of UV island
- - Same size of UV island
- - Same number of UV
- """
-
- bl_idname = "uv.muv_pack_uv_operator"
- bl_label = "Pack UV"
- bl_description = "Pack UV (Same UV Islands are integrated)"
- bl_options = {'REGISTER', 'UNDO'}
-
- rotate = BoolProperty(
- name="Rotate",
- description="Rotate option used by default pack UV function",
- default=False)
- margin = FloatProperty(
- name="Margin",
- description="Margin used by default pack UV function",
- min=0,
- max=1,
- default=0.001)
- allowable_center_deviation = FloatVectorProperty(
- name="Allowable Center Deviation",
- description="Allowable center deviation to judge same UV island",
- min=0.000001,
- max=0.1,
- default=(0.001, 0.001),
- size=2
- )
- allowable_size_deviation = FloatVectorProperty(
- name="Allowable Size Deviation",
- description="Allowable sizse deviation to judge same UV island",
- min=0.000001,
- max=0.1,
- default=(0.001, 0.001),
- size=2
- )
-
- def __init__(self):
- self.__impl = impl.PackUVImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.PackUVImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/preserve_uv_aspect.py b/uv_magic_uv/legacy/op/preserve_uv_aspect.py
deleted file mode 100644
index c6693e9a..00000000
--- a/uv_magic_uv/legacy/op/preserve_uv_aspect.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import StringProperty, EnumProperty, BoolProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import preserve_uv_aspect_impl as impl
-
-
-__all__ = [
- 'Properties',
- 'MUV_OT_PreserveUVAspect',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "preserve_uv_aspect"
-
- @classmethod
- def init_props(cls, scene):
- def get_loaded_texture_name(_, __):
- items = [(key, key, "") for key in bpy.data.images.keys()]
- items.append(("None", "None", ""))
- return items
-
- scene.muv_preserve_uv_aspect_enabled = BoolProperty(
- name="Preserve UV Aspect Enabled",
- description="Preserve UV Aspect is enabled",
- default=False
- )
- scene.muv_preserve_uv_aspect_tex_image = EnumProperty(
- name="Image",
- description="Texture Image",
- items=get_loaded_texture_name
- )
- scene.muv_preserve_uv_aspect_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 del_props(cls, scene):
- del scene.muv_preserve_uv_aspect_enabled
- del scene.muv_preserve_uv_aspect_tex_image
- del scene.muv_preserve_uv_aspect_origin
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_PreserveUVAspect(bpy.types.Operator):
- """
- Operation class: Preserve UV Aspect
- """
-
- bl_idname = "uv.muv_preserve_uv_aspect_operator"
- bl_label = "Preserve UV Aspect"
- bl_description = "Choose Image"
- 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"
- )
-
- def __init__(self):
- self.__impl = impl.PreserveUVAspectLegacyImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.PreserveUVAspectLegacyImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/select_uv.py b/uv_magic_uv/legacy/op/select_uv.py
deleted file mode 100644
index c4a7639d..00000000
--- a/uv_magic_uv/legacy/op/select_uv.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import select_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "select_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_select_uv_enabled = BoolProperty(
- name="Select UV Enabled",
- description="Select UV is enabled",
- default=False
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_select_uv_enabled
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
- """
- Operation class: Select faces which have overlapped UVs
- """
-
- bl_idname = "uv.muv_select_uv_operator_select_overlapped"
- bl_label = "Overlapped"
- bl_description = "Select faces which have overlapped UVs"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.SelectOverlappedImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.SelectOverlappedImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
- """
- Operation class: Select faces which have flipped UVs
- """
-
- bl_idname = "uv.muv_select_uv_operator_select_flipped"
- bl_label = "Flipped"
- bl_description = "Select faces which have flipped UVs"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.SelectFlippedImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.SelectFlippedImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/smooth_uv.py b/uv_magic_uv/legacy/op/smooth_uv.py
deleted file mode 100644
index 2e80e98c..00000000
--- a/uv_magic_uv/legacy/op/smooth_uv.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# <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__ = "imdjs, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty, FloatProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import smooth_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "smooth_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_smooth_uv_enabled = BoolProperty(
- name="Smooth UV Enabled",
- description="Smooth UV is enabled",
- default=False
- )
- scene.muv_smooth_uv_transmission = BoolProperty(
- name="Transmission",
- description="Smooth linked UVs",
- default=False
- )
- scene.muv_smooth_uv_mesh_infl = FloatProperty(
- name="Mesh Influence",
- description="Influence rate of mesh vertex",
- min=0.0,
- max=1.0,
- default=0.0
- )
- scene.muv_smooth_uv_select = BoolProperty(
- name="Select",
- description="Select UVs which are smoothed",
- default=False
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_smooth_uv_enabled
- del scene.muv_smooth_uv_transmission
- del scene.muv_smooth_uv_mesh_infl
- del scene.muv_smooth_uv_select
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_SmoothUV(bpy.types.Operator):
-
- bl_idname = "uv.muv_smooth_uv_operator"
- bl_label = "Smooth"
- bl_description = "Smooth UV coordinates"
- bl_options = {'REGISTER', 'UNDO'}
-
- transmission = BoolProperty(
- name="Transmission",
- description="Smooth linked UVs",
- default=False
- )
- mesh_infl = FloatProperty(
- name="Mesh Influence",
- description="Influence rate of mesh vertex",
- min=0.0,
- max=1.0,
- default=0.0
- )
- select = BoolProperty(
- name="Select",
- description="Select UVs which are smoothed",
- default=False
- )
-
- def __init__(self):
- self.__impl = impl.SmoothUVImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.SmoothUVImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/texture_lock.py b/uv_magic_uv/legacy/op/texture_lock.py
deleted file mode 100644
index ab06baf5..00000000
--- a/uv_magic_uv/legacy/op/texture_lock.py
+++ /dev/null
@@ -1,158 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import BoolProperty
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import texture_lock_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "texture_lock"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- verts_orig = None
-
- scene.muv_props.texture_lock = Props()
-
- def get_func(_):
- return MUV_OT_TextureLock_Intr.is_running(bpy.context)
-
- def set_func(_, __):
- pass
-
- def update_func(_, __):
- bpy.ops.uv.muv_texture_lock_operator_intr('INVOKE_REGION_WIN')
-
- scene.muv_texture_lock_enabled = BoolProperty(
- name="Texture Lock Enabled",
- description="Texture Lock is enabled",
- default=False
- )
- scene.muv_texture_lock_lock = BoolProperty(
- name="Texture Lock Locked",
- description="Texture Lock is locked",
- default=False,
- get=get_func,
- set=set_func,
- update=update_func
- )
- scene.muv_texture_lock_connect = BoolProperty(
- name="Connect UV",
- default=True
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_props.texture_lock
- del scene.muv_texture_lock_enabled
- del scene.muv_texture_lock_lock
- del scene.muv_texture_lock_connect
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureLock_Lock(bpy.types.Operator):
- """
- Operation class: Lock Texture
- """
-
- bl_idname = "uv.muv_texture_lock_operator_lock"
- bl_label = "Lock Texture"
- bl_description = "Lock Texture"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.LockImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.LockImpl.poll(context)
-
- @classmethod
- def is_ready(cls, context):
- return impl.LockImpl.is_ready(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureLock_Unlock(bpy.types.Operator):
- """
- Operation class: Unlock Texture
- """
-
- bl_idname = "uv.muv_texture_lock_operator_unlock"
- bl_label = "Unlock Texture"
- bl_description = "Unlock Texture"
- bl_options = {'REGISTER', 'UNDO'}
-
- connect = BoolProperty(
- name="Connect UV",
- default=True
- )
-
- def __init__(self):
- self.__impl = impl.UnlockImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.UnlockImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureLock_Intr(bpy.types.Operator):
- """
- Operation class: Texture Lock (Interactive mode)
- """
-
- bl_idname = "uv.muv_texture_lock_operator_intr"
- bl_label = "Texture Lock (Interactive mode)"
- bl_description = "Internal operation for Texture Lock (Interactive mode)"
-
- def __init__(self):
- self.__impl = impl.IntrImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.IntrImpl.poll(context)
-
- @classmethod
- def is_running(cls, context):
- return impl.IntrImpl.is_running(context)
-
- def modal(self, context, event):
- return self.__impl.modal(self, context, event)
-
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
diff --git a/uv_magic_uv/legacy/op/texture_projection.py b/uv_magic_uv/legacy/op/texture_projection.py
deleted file mode 100644
index bb73138b..00000000
--- a/uv_magic_uv/legacy/op/texture_projection.py
+++ /dev/null
@@ -1,296 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bgl
-import bmesh
-from bpy_extras import view3d_utils
-from bpy.props import (
- BoolProperty,
- EnumProperty,
- FloatProperty,
-)
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import texture_projection_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "texture_projection"
-
- @classmethod
- def init_props(cls, scene):
- def get_func(_):
- return MUV_OT_TextureProjection.is_running(bpy.context)
-
- def set_func(_, __):
- pass
-
- def update_func(_, __):
- bpy.ops.uv.muv_texture_projection_operator('INVOKE_REGION_WIN')
-
- scene.muv_texture_projection_enabled = BoolProperty(
- name="Texture Projection Enabled",
- description="Texture Projection is enabled",
- default=False
- )
- scene.muv_texture_projection_enable = BoolProperty(
- name="Texture Projection Enabled",
- description="Texture Projection is enabled",
- default=False,
- get=get_func,
- set=set_func,
- update=update_func
- )
- scene.muv_texture_projection_tex_magnitude = FloatProperty(
- name="Magnitude",
- description="Texture Magnitude",
- default=0.5,
- min=0.0,
- max=100.0
- )
- scene.muv_texture_projection_tex_image = EnumProperty(
- name="Image",
- description="Texture Image",
- items=impl.get_loaded_texture_name
- )
- scene.muv_texture_projection_tex_transparency = FloatProperty(
- name="Transparency",
- description="Texture Transparency",
- default=0.2,
- min=0.0,
- max=1.0
- )
- scene.muv_texture_projection_adjust_window = BoolProperty(
- name="Adjust Window",
- description="Size of renderered texture is fitted to window",
- default=True
- )
- scene.muv_texture_projection_apply_tex_aspect = BoolProperty(
- name="Texture Aspect Ratio",
- description="Apply Texture Aspect ratio to displayed texture",
- default=True
- )
- scene.muv_texture_projection_assign_uvmap = BoolProperty(
- name="Assign UVMap",
- description="Assign UVMap when no UVmaps are available",
- default=True
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_texture_projection_enabled
- del scene.muv_texture_projection_tex_magnitude
- del scene.muv_texture_projection_tex_image
- del scene.muv_texture_projection_tex_transparency
- del scene.muv_texture_projection_adjust_window
- del scene.muv_texture_projection_apply_tex_aspect
- del scene.muv_texture_projection_assign_uvmap
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureProjection(bpy.types.Operator):
- """
- Operation class: Texture Projection
- Render texture
- """
-
- bl_idname = "uv.muv_texture_projection_operator"
- bl_description = "Render selected texture"
- bl_label = "Texture renderer"
-
- __handle = None
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return False
- return impl.is_valid_context(context)
-
- @classmethod
- def is_running(cls, _):
- return 1 if cls.__handle else 0
-
- @classmethod
- def handle_add(cls, obj, context):
- cls.__handle = bpy.types.SpaceView3D.draw_handler_add(
- MUV_OT_TextureProjection.draw_texture,
- (obj, context), 'WINDOW', 'POST_PIXEL')
-
- @classmethod
- def handle_remove(cls):
- if cls.__handle is not None:
- bpy.types.SpaceView3D.draw_handler_remove(cls.__handle, 'WINDOW')
- cls.__handle = None
-
- @classmethod
- def draw_texture(cls, _, context):
- sc = context.scene
-
- if not cls.is_running(context):
- return
-
- # no textures are selected
- if sc.muv_texture_projection_tex_image == "None":
- return
-
- # get texture to be renderred
- img = bpy.data.images[sc.muv_texture_projection_tex_image]
-
- # setup rendering region
- rect = impl.get_canvas(context, sc.muv_texture_projection_tex_magnitude)
- positions = [
- [rect.x0, rect.y0],
- [rect.x0, rect.y1],
- [rect.x1, rect.y1],
- [rect.x1, rect.y0]
- ]
- tex_coords = [
- [0.0, 0.0],
- [0.0, 1.0],
- [1.0, 1.0],
- [1.0, 0.0]
- ]
-
- # OpenGL configuration
- bgl.glEnable(bgl.GL_BLEND)
- bgl.glEnable(bgl.GL_TEXTURE_2D)
- if img.bindcode:
- bind = img.bindcode[0]
- bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
- bgl.glTexParameteri(
- bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR)
- bgl.glTexParameteri(
- bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR)
- bgl.glTexEnvi(
- bgl.GL_TEXTURE_ENV, bgl.GL_TEXTURE_ENV_MODE, bgl.GL_MODULATE)
-
- # render texture
- bgl.glBegin(bgl.GL_QUADS)
- bgl.glColor4f(1.0, 1.0, 1.0,
- sc.muv_texture_projection_tex_transparency)
- for (v1, v2), (u, v) in zip(positions, tex_coords):
- bgl.glTexCoord2f(u, v)
- bgl.glVertex2f(v1, v2)
- bgl.glEnd()
-
- def invoke(self, context, _):
- if not MUV_OT_TextureProjection.is_running(context):
- MUV_OT_TextureProjection.handle_add(self, context)
- else:
- MUV_OT_TextureProjection.handle_remove()
-
- if context.area:
- context.area.tag_redraw()
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureProjection_Project(bpy.types.Operator):
- """
- Operation class: Project texture
- """
-
- bl_idname = "uv.muv_texture_projection_operator_project"
- bl_label = "Project Texture"
- bl_description = "Project Texture"
- bl_options = {'REGISTER', 'UNDO'}
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- if not MUV_OT_TextureProjection.is_running(context):
- return False
- return impl.is_valid_context(context)
-
- def execute(self, context):
- sc = context.scene
-
- if sc.muv_texture_projection_tex_image == "None":
- self.report({'WARNING'}, "No textures are selected")
- return {'CANCELLED'}
-
- _, region, space = common.get_space_legacy(
- 'VIEW_3D', 'WINDOW', 'VIEW_3D')
-
- # get faces to be texture projected
- obj = context.active_object
- world_mat = obj.matrix_world
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- # get UV and texture layer
- if not bm.loops.layers.uv:
- if sc.muv_texture_projection_assign_uvmap:
- bm.loops.layers.uv.new()
- else:
- self.report({'WARNING'},
- "Object must have more than one UV map")
- return {'CANCELLED'}
-
- uv_layer = bm.loops.layers.uv.verify()
- tex_layer = bm.faces.layers.tex.verify()
-
- sel_faces = [f for f in bm.faces if f.select]
-
- # transform 3d space to screen region
- v_screen = [
- view3d_utils.location_3d_to_region_2d(
- region,
- space.region_3d,
- world_mat * l.vert.co)
- for f in sel_faces for l in f.loops
- ]
-
- # transform screen region to canvas
- v_canvas = [
- impl.region_to_canvas(
- v,
- impl.get_canvas(bpy.context,
- sc.muv_texture_projection_tex_magnitude)
- ) for v in v_screen
- ]
-
- # project texture to object
- i = 0
- for f in sel_faces:
- f[tex_layer].image = \
- bpy.data.images[sc.muv_texture_projection_tex_image]
- for l in f.loops:
- l[uv_layer].uv = v_canvas[i].to_2d()
- i = i + 1
-
- common.redraw_all_areas()
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/texture_wrap.py b/uv_magic_uv/legacy/op/texture_wrap.py
deleted file mode 100644
index 85c9d174..00000000
--- a/uv_magic_uv/legacy/op/texture_wrap.py
+++ /dev/null
@@ -1,113 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
- BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import texture_wrap_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "texture_wrap"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- ref_face_index = -1
- ref_obj = None
-
- scene.muv_props.texture_wrap = Props()
-
- scene.muv_texture_wrap_enabled = BoolProperty(
- name="Texture Wrap",
- description="Texture Wrap is enabled",
- default=False
- )
- scene.muv_texture_wrap_set_and_refer = BoolProperty(
- name="Set and Refer",
- description="Refer and set UV",
- default=True
- )
- scene.muv_texture_wrap_selseq = BoolProperty(
- name="Selection Sequence",
- description="Set UV sequentially",
- default=False
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_props.texture_wrap
- del scene.muv_texture_wrap_enabled
- del scene.muv_texture_wrap_set_and_refer
- del scene.muv_texture_wrap_selseq
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureWrap_Refer(bpy.types.Operator):
- """
- Operation class: Refer UV
- """
-
- bl_idname = "uv.muv_texture_wrap_operator_refer"
- bl_label = "Refer"
- bl_description = "Refer UV"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.ReferImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.ReferImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TextureWrap_Set(bpy.types.Operator):
- """
- Operation class: Set UV
- """
-
- bl_idname = "uv.muv_texture_wrap_operator_set"
- bl_label = "Set"
- bl_description = "Set UV"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.SetImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.SetImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/transfer_uv.py b/uv_magic_uv/legacy/op/transfer_uv.py
deleted file mode 100644
index cd0e4dd9..00000000
--- a/uv_magic_uv/legacy/op/transfer_uv.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>, Mifth, MaxRobinot"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from bpy.props import BoolProperty
-
-from ... import common
-from ...impl import transfer_uv_impl as impl
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
- 'Properties',
- 'MUV_OT_TransferUV_CopyUV',
- 'MUV_OT_TransferUV_PasteUV',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "transfer_uv"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- topology_copied = None
-
- scene.muv_props.transfer_uv = Props()
-
- scene.muv_transfer_uv_enabled = BoolProperty(
- name="Transfer UV Enabled",
- description="Transfer UV is enabled",
- default=False
- )
- scene.muv_transfer_uv_invert_normals = BoolProperty(
- name="Invert Normals",
- description="Invert Normals",
- default=False
- )
- scene.muv_transfer_uv_copy_seams = BoolProperty(
- name="Copy Seams",
- description="Copy Seams",
- default=True
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_transfer_uv_enabled
- del scene.muv_transfer_uv_invert_normals
- del scene.muv_transfer_uv_copy_seams
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TransferUV_CopyUV(bpy.types.Operator):
- """
- Operation class: Transfer UV copy
- Topological based copy
- """
-
- bl_idname = "uv.muv_transfer_uv_operator_copy_uv"
- bl_label = "Transfer UV Copy UV"
- bl_description = "Transfer UV Copy UV (Topological based copy)"
- bl_options = {'REGISTER', 'UNDO'}
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return impl.is_valid_context(context)
-
- def execute(self, context):
- props = context.scene.muv_props.transfer_uv
- active_obj = context.scene.objects.active
- bm = bmesh.from_edit_mesh(active_obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- uv_layer = impl.get_uv_layer(self, bm)
- if uv_layer is None:
- return {'CANCELLED'}
-
- faces = impl.get_selected_src_faces(self, bm, uv_layer)
- if faces is None:
- return {'CANCELLED'}
- props.topology_copied = faces
-
- bmesh.update_edit_mesh(active_obj.data)
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
- """
- Operation class: Transfer UV paste
- Topological based paste
- """
-
- bl_idname = "uv.muv_transfer_uv_operator_paste_uv"
- bl_label = "Transfer UV Paste UV"
- bl_description = "Transfer UV Paste UV (Topological based paste)"
- bl_options = {'REGISTER', 'UNDO'}
-
- invert_normals = BoolProperty(
- name="Invert Normals",
- description="Invert Normals",
- default=False
- )
- copy_seams = BoolProperty(
- name="Copy Seams",
- description="Copy Seams",
- default=True
- )
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- sc = context.scene
- props = sc.muv_props.transfer_uv
- if not props.topology_copied:
- return False
- return impl.is_valid_context(context)
-
- def execute(self, context):
- props = context.scene.muv_props.transfer_uv
- active_obj = context.scene.objects.active
- bm = bmesh.from_edit_mesh(active_obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- # get UV layer
- uv_layer = impl.get_uv_layer(self, bm)
- if uv_layer is None:
- return {'CANCELLED'}
-
- ret = impl.paste_uv(self, bm, uv_layer, props.topology_copied,
- self.invert_normals, self.copy_seams)
- if ret:
- return {'CANCELLED'}
-
- bmesh.update_edit_mesh(active_obj.data)
- if self.copy_seams:
- active_obj.data.show_edge_seams = True
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/unwrap_constraint.py b/uv_magic_uv/legacy/op/unwrap_constraint.py
deleted file mode 100644
index b7faa77a..00000000
--- a/uv_magic_uv/legacy/op/unwrap_constraint.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# ##### 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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
- BoolProperty,
- EnumProperty,
- FloatProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import unwrap_constraint_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "unwrap_constraint"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_unwrap_constraint_enabled = BoolProperty(
- name="Unwrap Constraint Enabled",
- description="Unwrap Constraint is enabled",
- default=False
- )
- scene.muv_unwrap_constraint_u_const = BoolProperty(
- name="U-Constraint",
- description="Keep UV U-axis coordinate",
- default=False
- )
- scene.muv_unwrap_constraint_v_const = BoolProperty(
- name="V-Constraint",
- description="Keep UV V-axis coordinate",
- default=False
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_unwrap_constraint_enabled
- del scene.muv_unwrap_constraint_u_const
- del scene.muv_unwrap_constraint_v_const
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UnwrapConstraint(bpy.types.Operator):
- """
- Operation class: Unwrap with constrain UV coordinate
- """
-
- bl_idname = "uv.muv_unwrap_constraint_operator"
- bl_label = "Unwrap Constraint"
- bl_description = "Unwrap while keeping uv coordinate"
- bl_options = {'REGISTER', 'UNDO'}
-
- # property for original unwrap
- method = EnumProperty(
- name="Method",
- description="Unwrapping method",
- items=[
- ('ANGLE_BASED', 'Angle Based', 'Angle Based'),
- ('CONFORMAL', 'Conformal', 'Conformal')
- ],
- default='ANGLE_BASED')
- fill_holes = BoolProperty(
- name="Fill Holes",
- description="Virtual fill holes in meshes before unwrapping",
- default=True)
- correct_aspect = BoolProperty(
- name="Correct Aspect",
- description="Map UVs taking image aspect ratio into account",
- default=True)
- use_subsurf_data = BoolProperty(
- name="Use Subsurf Modifier",
- description="""Map UVs taking vertex position after subsurf
- into account""",
- default=False)
- margin = FloatProperty(
- name="Margin",
- description="Space between islands",
- max=1.0,
- min=0.0,
- default=0.001)
-
- # property for this operation
- u_const = BoolProperty(
- name="U-Constraint",
- description="Keep UV U-axis coordinate",
- default=False
- )
- v_const = BoolProperty(
- name="V-Constraint",
- description="Keep UV V-axis coordinate",
- default=False
- )
-
- def __init__(self):
- self.__impl = impl.UnwrapConstraintImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.UnwrapConstraintImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/op/uv_bounding_box.py b/uv_magic_uv/legacy/op/uv_bounding_box.py
deleted file mode 100644
index 74c5f15c..00000000
--- a/uv_magic_uv/legacy/op/uv_bounding_box.py
+++ /dev/null
@@ -1,810 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-from enum import IntEnum
-import math
-
-import bpy
-import bgl
-import mathutils
-import bmesh
-from bpy.props import BoolProperty, EnumProperty
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import uv_bounding_box_impl as impl
-
-
-MAX_VALUE = 100000.0
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "uv_bounding_box"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- uv_info_ini = []
- ctrl_points_ini = []
- ctrl_points = []
-
- scene.muv_props.uv_bounding_box = Props()
-
- def get_func(_):
- return MUV_OT_UVBoundingBox.is_running(bpy.context)
-
- def set_func(_, __):
- pass
-
- def update_func(_, __):
- bpy.ops.uv.muv_uv_bounding_box_operator('INVOKE_REGION_WIN')
-
- scene.muv_uv_bounding_box_enabled = BoolProperty(
- name="UV Bounding Box Enabled",
- description="UV Bounding Box is enabled",
- default=False
- )
- scene.muv_uv_bounding_box_show = BoolProperty(
- name="UV Bounding Box Showed",
- description="UV Bounding Box is showed",
- default=False,
- get=get_func,
- set=set_func,
- update=update_func
- )
- scene.muv_uv_bounding_box_uniform_scaling = BoolProperty(
- name="Uniform Scaling",
- description="Enable Uniform Scaling",
- default=False
- )
- scene.muv_uv_bounding_box_boundary = EnumProperty(
- name="Boundary",
- description="Boundary",
- default='UV_SEL',
- items=[
- ('UV', "UV", "Boundary is decided by UV"),
- ('UV_SEL', "UV (Selected)",
- "Boundary is decided by Selected UV")
- ]
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_props.uv_bounding_box
- del scene.muv_uv_bounding_box_enabled
- del scene.muv_uv_bounding_box_show
- del scene.muv_uv_bounding_box_uniform_scaling
- del scene.muv_uv_bounding_box_boundary
-
-
-class CommandBase:
- """
- Custom class: Base class of command
- """
-
- def __init__(self):
- self.op = 'NONE' # operation
-
- def to_matrix(self):
- # mat = I
- mat = mathutils.Matrix()
- mat.identity()
- return mat
-
-
-class TranslationCommand(CommandBase):
- """
- Custom class: Translation operation
- """
-
- def __init__(self, ix, iy):
- super().__init__()
- self.op = 'TRANSLATION'
- self.__x = ix # current x
- self.__y = iy # current y
- self.__ix = ix # initial x
- self.__iy = iy # initial y
-
- def to_matrix(self):
- # mat = Mt
- dx = self.__x - self.__ix
- dy = self.__y - self.__iy
- return mathutils.Matrix.Translation((dx, dy, 0))
-
- def set(self, x, y):
- self.__x = x
- self.__y = y
-
-
-class RotationCommand(CommandBase):
- """
- Custom class: Rotation operation
- """
-
- def __init__(self, ix, iy, cx, cy):
- super().__init__()
- self.op = 'ROTATION'
- self.__x = ix # current x
- self.__y = iy # current y
- self.__cx = cx # center of rotation x
- self.__cy = cy # center of rotation y
- dx = self.__x - self.__cx
- dy = self.__y - self.__cy
- self.__iangle = math.atan2(dy, dx) # initial rotation angle
-
- def to_matrix(self):
- # mat = Mt * Mr * Mt^-1
- dx = self.__x - self.__cx
- dy = self.__y - self.__cy
- angle = math.atan2(dy, dx) - self.__iangle
- mti = mathutils.Matrix.Translation((-self.__cx, -self.__cy, 0.0))
- mr = mathutils.Matrix.Rotation(angle, 4, 'Z')
- mt = mathutils.Matrix.Translation((self.__cx, self.__cy, 0.0))
- return mt * mr * mti
-
- def set(self, x, y):
- self.__x = x
- self.__y = y
-
-
-class ScalingCommand(CommandBase):
- """
- Custom class: Scaling operation
- """
-
- def __init__(self, ix, iy, ox, oy, dir_x, dir_y, mat):
- super().__init__()
- self.op = 'SCALING'
- self.__ix = ix # initial x
- self.__iy = iy # initial y
- self.__x = ix # current x
- self.__y = iy # current y
- self.__ox = ox # origin of scaling x
- self.__oy = oy # origin of scaling y
- self.__dir_x = dir_x # direction of scaling x
- self.__dir_y = dir_y # direction of scaling y
- self.__mat = mat
- # initial origin of scaling = M(to original transform) * (ox, oy)
- iov = mat * mathutils.Vector((ox, oy, 0.0))
- self.__iox = iov.x # initial origin of scaling X
- self.__ioy = iov.y # initial origin of scaling y
-
- def to_matrix(self):
- """
- mat = M(to original transform)^-1 * Mt(to origin) * Ms *
- Mt(to origin)^-1 * M(to original transform)
- """
- m = self.__mat
- mi = self.__mat.inverted()
- mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
- mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
- # every point must be transformed to origin
- t = m * mathutils.Vector((self.__ix, self.__iy, 0.0))
- tix, tiy = t.x, t.y
- t = m * mathutils.Vector((self.__ox, self.__oy, 0.0))
- tox, toy = t.x, t.y
- t = m * mathutils.Vector((self.__x, self.__y, 0.0))
- tx, ty = t.x, t.y
- ms = mathutils.Matrix()
- ms.identity()
- if self.__dir_x == 1:
- ms[0][0] = (tx - tox) * self.__dir_x / (tix - tox)
- if self.__dir_y == 1:
- ms[1][1] = (ty - toy) * self.__dir_y / (tiy - toy)
- return mi * mto * ms * mtoi * m
-
- def set(self, x, y):
- self.__x = x
- self.__y = y
-
-
-class UniformScalingCommand(CommandBase):
- """
- Custom class: Uniform Scaling operation
- """
-
- def __init__(self, ix, iy, ox, oy, mat):
- super().__init__()
- self.op = 'SCALING'
- self.__ix = ix # initial x
- self.__iy = iy # initial y
- self.__x = ix # current x
- self.__y = iy # current y
- self.__ox = ox # origin of scaling x
- self.__oy = oy # origin of scaling y
- self.__mat = mat
- # initial origin of scaling = M(to original transform) * (ox, oy)
- iov = mat * mathutils.Vector((ox, oy, 0.0))
- self.__iox = iov.x # initial origin of scaling x
- self.__ioy = iov.y # initial origin of scaling y
- self.__dir_x = 1
- self.__dir_y = 1
-
- def to_matrix(self):
- """
- mat = M(to original transform)^-1 * Mt(to origin) * Ms *
- Mt(to origin)^-1 * M(to original transform)
- """
- m = self.__mat
- mi = self.__mat.inverted()
- mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
- mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
- # every point must be transformed to origin
- t = m * mathutils.Vector((self.__ix, self.__iy, 0.0))
- tix, tiy = t.x, t.y
- t = m * mathutils.Vector((self.__ox, self.__oy, 0.0))
- tox, toy = t.x, t.y
- t = m * mathutils.Vector((self.__x, self.__y, 0.0))
- tx, ty = t.x, t.y
- ms = mathutils.Matrix()
- ms.identity()
- tir = math.sqrt((tix - tox) * (tix - tox) + (tiy - toy) * (tiy - toy))
- tr = math.sqrt((tx - tox) * (tx - tox) + (ty - toy) * (ty - toy))
-
- sr = tr / tir
-
- if ((tx - tox) * (tix - tox)) > 0:
- self.__dir_x = 1
- else:
- self.__dir_x = -1
- if ((ty - toy) * (tiy - toy)) > 0:
- self.__dir_y = 1
- else:
- self.__dir_y = -1
-
- ms[0][0] = sr * self.__dir_x
- ms[1][1] = sr * self.__dir_y
-
- return mi * mto * ms * mtoi * m
-
- def set(self, x, y):
- self.__x = x
- self.__y = y
-
-
-class CommandExecuter:
- """
- Custom class: manage command history and execute command
- """
-
- def __init__(self):
- self.__cmd_list = [] # history
- self.__cmd_list_redo = [] # redo list
-
- def execute(self, begin=0, end=-1):
- """
- create matrix from history
- """
- mat = mathutils.Matrix()
- mat.identity()
- for i, cmd in enumerate(self.__cmd_list):
- if begin <= i and (end == -1 or i <= end):
- mat = cmd.to_matrix() * mat
- return mat
-
- def undo_size(self):
- """
- get history size
- """
- return len(self.__cmd_list)
-
- def top(self):
- """
- get top of history
- """
- if len(self.__cmd_list) <= 0:
- return None
- return self.__cmd_list[-1]
-
- def append(self, cmd):
- """
- append command
- """
- self.__cmd_list.append(cmd)
- self.__cmd_list_redo = []
-
- def undo(self):
- """
- undo command
- """
- if len(self.__cmd_list) <= 0:
- return
- self.__cmd_list_redo.append(self.__cmd_list.pop())
-
- def redo(self):
- """
- redo command
- """
- if len(self.__cmd_list_redo) <= 0:
- return
- self.__cmd_list.append(self.__cmd_list_redo.pop())
-
- def pop(self):
- if len(self.__cmd_list) <= 0:
- return None
- return self.__cmd_list.pop()
-
- def push(self, cmd):
- self.__cmd_list.append(cmd)
-
-
-class State(IntEnum):
- """
- Enum: State definition used by MUV_UVBBStateMgr
- """
- NONE = 0
- TRANSLATING = 1
- SCALING_1 = 2
- SCALING_2 = 3
- SCALING_3 = 4
- SCALING_4 = 5
- SCALING_5 = 6
- SCALING_6 = 7
- SCALING_7 = 8
- SCALING_8 = 9
- ROTATING = 10
- UNIFORM_SCALING_1 = 11
- UNIFORM_SCALING_2 = 12
- UNIFORM_SCALING_3 = 13
- UNIFORM_SCALING_4 = 14
-
-
-class StateBase:
- """
- Custom class: Base class of state
- """
-
- def __init__(self):
- pass
-
- def update(self, context, event, ctrl_points, mouse_view):
- raise NotImplementedError
-
-
-class StateNone(StateBase):
- """
- Custom class:
- No state
- Wait for event from mouse
- """
-
- def __init__(self, cmd_exec):
- super().__init__()
- self.__cmd_exec = cmd_exec
-
- def update(self, context, event, ctrl_points, mouse_view):
- """
- Update state
- """
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
- cp_react_size = prefs.uv_bounding_box_cp_react_size
- is_uscaling = context.scene.muv_uv_bounding_box_uniform_scaling
- 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 (
- State.UNIFORM_SCALING_1 +
- arr.index(i)
- )
- else:
- return State.TRANSLATING + i
-
- return State.NONE
-
-
-class StateTranslating(StateBase):
- """
- Custom class: Translating state
- """
-
- def __init__(self, cmd_exec, ctrl_points):
- super().__init__()
- self.__cmd_exec = cmd_exec
- ix, iy = ctrl_points[0].x, ctrl_points[0].y
- self.__cmd_exec.append(TranslationCommand(ix, iy))
-
- def update(self, context, event, ctrl_points, mouse_view):
- if event.type == 'LEFTMOUSE':
- if event.value == 'RELEASE':
- return State.NONE
- if event.type == 'MOUSEMOVE':
- x, y = mouse_view.x, mouse_view.y
- self.__cmd_exec.top().set(x, y)
- return State.TRANSLATING
-
-
-class StateScaling(StateBase):
- """
- Custom class: Scaling state
- """
-
- def __init__(self, cmd_exec, state, ctrl_points):
- super().__init__()
- self.__state = state
- self.__cmd_exec = cmd_exec
- dir_x_list = [1, 1, 1, 0, 0, 1, 1, 1]
- dir_y_list = [1, 0, 1, 1, 1, 1, 0, 1]
- idx = state - 2
- ix, iy = ctrl_points[idx + 1].x, ctrl_points[idx + 1].y
- ox, oy = ctrl_points[8 - idx].x, ctrl_points[8 - idx].y
- dir_x, dir_y = dir_x_list[idx], dir_y_list[idx]
- mat = self.__cmd_exec.execute(end=self.__cmd_exec.undo_size())
- self.__cmd_exec.append(
- ScalingCommand(ix, iy, ox, oy, dir_x, dir_y, mat.inverted()))
-
- def update(self, context, event, ctrl_points, mouse_view):
- if event.type == 'LEFTMOUSE':
- if event.value == 'RELEASE':
- return State.NONE
- if event.type == 'MOUSEMOVE':
- x, y = mouse_view.x, mouse_view.y
- self.__cmd_exec.top().set(x, y)
- return self.__state
-
-
-class StateUniformScaling(StateBase):
- """
- Custom class: Uniform Scaling state
- """
-
- def __init__(self, cmd_exec, state, ctrl_points):
- super().__init__()
- self.__state = state
- self.__cmd_exec = cmd_exec
- icp_idx = [1, 3, 6, 8]
- ocp_idx = [8, 6, 3, 1]
- idx = state - State.UNIFORM_SCALING_1
- ix, iy = ctrl_points[icp_idx[idx]].x, ctrl_points[icp_idx[idx]].y
- ox, oy = ctrl_points[ocp_idx[idx]].x, ctrl_points[ocp_idx[idx]].y
- mat = self.__cmd_exec.execute(end=self.__cmd_exec.undo_size())
- self.__cmd_exec.append(UniformScalingCommand(
- ix, iy, ox, oy, mat.inverted()))
-
- def update(self, context, event, ctrl_points, mouse_view):
- if event.type == 'LEFTMOUSE':
- if event.value == 'RELEASE':
- return State.NONE
- if event.type == 'MOUSEMOVE':
- x, y = mouse_view.x, mouse_view.y
- self.__cmd_exec.top().set(x, y)
-
- return self.__state
-
-
-class StateRotating(StateBase):
- """
- Custom class: Rotating state
- """
-
- def __init__(self, cmd_exec, ctrl_points):
- super().__init__()
- self.__cmd_exec = cmd_exec
- ix, iy = ctrl_points[9].x, ctrl_points[9].y
- ox, oy = ctrl_points[0].x, ctrl_points[0].y
- self.__cmd_exec.append(RotationCommand(ix, iy, ox, oy))
-
- def update(self, context, event, ctrl_points, mouse_view):
- if event.type == 'LEFTMOUSE':
- if event.value == 'RELEASE':
- return State.NONE
- if event.type == 'MOUSEMOVE':
- x, y = mouse_view.x, mouse_view.y
- self.__cmd_exec.top().set(x, y)
- return State.ROTATING
-
-
-class StateManager:
- """
- Custom class: Manage state about this feature
- """
-
- def __init__(self, cmd_exec):
- self.__cmd_exec = cmd_exec # command executer
- self.__state = State.NONE # current state
- self.__state_obj = StateNone(self.__cmd_exec)
-
- def __update_state(self, next_state, ctrl_points):
- """
- Update state
- """
-
- if next_state == self.__state:
- return
- obj = None
- if next_state == State.TRANSLATING:
- obj = StateTranslating(self.__cmd_exec, ctrl_points)
- elif State.SCALING_1 <= next_state <= State.SCALING_8:
- obj = StateScaling(
- self.__cmd_exec, next_state, ctrl_points)
- elif next_state == State.ROTATING:
- obj = StateRotating(self.__cmd_exec, ctrl_points)
- elif next_state == State.NONE:
- obj = StateNone(self.__cmd_exec)
- elif (State.UNIFORM_SCALING_1 <= next_state <=
- State.UNIFORM_SCALING_4):
- obj = StateUniformScaling(
- self.__cmd_exec, next_state, ctrl_points)
-
- if obj is not None:
- self.__state_obj = obj
-
- self.__state = next_state
-
- def update(self, context, ctrl_points, event):
- mouse_region = mathutils.Vector((
- event.mouse_region_x, event.mouse_region_y))
- mouse_view = mathutils.Vector((context.region.view2d.region_to_view(
- mouse_region.x, mouse_region.y)))
- next_state = self.__state_obj.update(
- context, event, ctrl_points, mouse_view)
- self.__update_state(next_state, ctrl_points)
-
- return self.__state
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVBoundingBox(bpy.types.Operator):
- """
- Operation class: UV Bounding Box
- """
-
- bl_idname = "uv.muv_uv_bounding_box_operator"
- bl_label = "UV Bounding Box"
- bl_description = "Internal operation for UV Bounding Box"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__timer = None
- self.__cmd_exec = CommandExecuter() # Command executor
- self.__state_mgr = StateManager(self.__cmd_exec) # State Manager
-
- __handle = None
- __timer = None
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return False
- return impl.is_valid_context(context)
-
- @classmethod
- def is_running(cls, _):
- return 1 if cls.__handle else 0
-
- @classmethod
- def handle_add(cls, obj, context):
- if cls.__handle is None:
- sie = bpy.types.SpaceImageEditor
- cls.__handle = sie.draw_handler_add(
- cls.draw_bb, (obj, context), "WINDOW", "POST_PIXEL")
- if cls.__timer is None:
- cls.__timer = context.window_manager.event_timer_add(
- 0.1, window=context.window)
- context.window_manager.modal_handler_add(obj)
-
- @classmethod
- def handle_remove(cls, context):
- if cls.__handle is not None:
- sie = bpy.types.SpaceImageEditor
- sie.draw_handler_remove(cls.__handle, "WINDOW")
- cls.__handle = None
- if cls.__timer is not None:
- context.window_manager.event_timer_remove(cls.__timer)
- cls.__timer = None
-
- @classmethod
- def __draw_ctrl_point(cls, context, pos):
- """
- Draw control point
- """
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
- cp_size = prefs.uv_bounding_box_cp_size
- offset = cp_size / 2
- verts = [
- [pos.x - offset, pos.y - offset],
- [pos.x - offset, pos.y + offset],
- [pos.x + offset, pos.y + offset],
- [pos.x + offset, pos.y - offset]
- ]
- bgl.glEnable(bgl.GL_BLEND)
- bgl.glBegin(bgl.GL_QUADS)
- bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
- for (x, y) in verts:
- bgl.glVertex2f(x, y)
- bgl.glEnd()
-
- @classmethod
- def draw_bb(cls, _, context):
- """
- Draw bounding box
- """
- props = context.scene.muv_props.uv_bounding_box
-
- if not MUV_OT_UVBoundingBox.is_running(context):
- return
-
- if not impl.is_valid_context(context):
- return
-
- for cp in props.ctrl_points:
- cls.__draw_ctrl_point(
- context, mathutils.Vector(
- context.region.view2d.view_to_region(cp.x, cp.y)))
-
- def __get_uv_info(self, context):
- """
- Get UV coordinate
- """
- sc = context.scene
- obj = context.active_object
- uv_info = []
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- if not bm.loops.layers.uv:
- return None
- uv_layer = bm.loops.layers.uv.verify()
- for f in bm.faces:
- if not f.select:
- continue
- for i, l in enumerate(f.loops):
- if sc.muv_uv_bounding_box_boundary == 'UV_SEL':
- if l[uv_layer].select:
- uv_info.append((f.index, i, l[uv_layer].uv.copy()))
- elif sc.muv_uv_bounding_box_boundary == 'UV':
- uv_info.append((f.index, i, l[uv_layer].uv.copy()))
- if not uv_info:
- return None
- return uv_info
-
- def __get_ctrl_point(self, uv_info_ini):
- """
- Get control point
- """
- left = MAX_VALUE
- right = -MAX_VALUE
- top = -MAX_VALUE
- bottom = MAX_VALUE
-
- for info in uv_info_ini:
- uv = info[2]
- if uv.x < left:
- left = uv.x
- if uv.x > right:
- right = uv.x
- if uv.y < bottom:
- bottom = uv.y
- if uv.y > top:
- top = uv.y
-
- points = [
- mathutils.Vector((
- (left + right) * 0.5, (top + bottom) * 0.5, 0.0
- )),
- mathutils.Vector((left, top, 0.0)),
- mathutils.Vector((left, (top + bottom) * 0.5, 0.0)),
- mathutils.Vector((left, bottom, 0.0)),
- mathutils.Vector(((left + right) * 0.5, top, 0.0)),
- mathutils.Vector(((left + right) * 0.5, bottom, 0.0)),
- mathutils.Vector((right, top, 0.0)),
- mathutils.Vector((right, (top + bottom) * 0.5, 0.0)),
- mathutils.Vector((right, bottom, 0.0)),
- mathutils.Vector(((left + right) * 0.5, top + 0.03, 0.0))
- ]
-
- return points
-
- def __update_uvs(self, context, uv_info_ini, trans_mat):
- """
- Update UV coordinate
- """
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
- if not bm.loops.layers.uv:
- return
- uv_layer = bm.loops.layers.uv.verify()
- for info in uv_info_ini:
- fidx = info[0]
- lidx = info[1]
- uv = info[2]
- v = mathutils.Vector((uv.x, uv.y, 0.0))
- av = trans_mat * v
- bm.faces[fidx].loops[lidx][uv_layer].uv = mathutils.Vector(
- (av.x, av.y))
-
- def __update_ctrl_point(self, ctrl_points_ini, trans_mat):
- """
- Update control point
- """
- return [trans_mat * cp for cp in ctrl_points_ini]
-
- def modal(self, context, event):
- props = context.scene.muv_props.uv_bounding_box
- common.redraw_all_areas()
-
- if not MUV_OT_UVBoundingBox.is_running(context):
- return {'FINISHED'}
-
- if not impl.is_valid_context(context):
- MUV_OT_UVBoundingBox.handle_remove(context)
- return {'FINISHED'}
-
- region_types = [
- 'HEADER',
- 'UI',
- 'TOOLS',
- ]
- if not common.mouse_on_area_legacy(event, 'IMAGE_EDITOR') or \
- common.mouse_on_regions_legacy(event, 'IMAGE_EDITOR', region_types):
- return {'PASS_THROUGH'}
-
- if event.type == 'TIMER':
- trans_mat = self.__cmd_exec.execute()
- self.__update_uvs(context, props.uv_info_ini, trans_mat)
- props.ctrl_points = self.__update_ctrl_point(
- props.ctrl_points_ini, trans_mat)
-
- state = self.__state_mgr.update(context, props.ctrl_points, event)
- if state == State.NONE:
- return {'PASS_THROUGH'}
-
- return {'RUNNING_MODAL'}
-
- def invoke(self, context, _):
- props = context.scene.muv_props.uv_bounding_box
-
- if MUV_OT_UVBoundingBox.is_running(context):
- MUV_OT_UVBoundingBox.handle_remove(context)
- return {'FINISHED'}
-
- props.uv_info_ini = self.__get_uv_info(context)
- if props.uv_info_ini is None:
- return {'CANCELLED'}
-
- MUV_OT_UVBoundingBox.handle_add(self, context)
-
- props.ctrl_points_ini = self.__get_ctrl_point(props.uv_info_ini)
- trans_mat = self.__cmd_exec.execute()
- # Update is needed in order to display control point
- self.__update_uvs(context, props.uv_info_ini, trans_mat)
- props.ctrl_points = self.__update_ctrl_point(
- props.ctrl_points_ini, trans_mat)
-
- return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/legacy/op/uv_inspection.py b/uv_magic_uv/legacy/op/uv_inspection.py
deleted file mode 100644
index df7e17e9..00000000
--- a/uv_magic_uv/legacy/op/uv_inspection.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bgl
-from bpy.props import BoolProperty, EnumProperty
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import uv_inspection_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "uv_inspection"
-
- @classmethod
- def init_props(cls, scene):
- class Props():
- overlapped_info = []
- flipped_info = []
-
- scene.muv_props.uv_inspection = Props()
-
- def get_func(_):
- return MUV_OT_UVInspection_Render.is_running(bpy.context)
-
- def set_func(_, __):
- pass
-
- def update_func(_, __):
- bpy.ops.uv.muv_uv_inspection_operator_render('INVOKE_REGION_WIN')
-
- scene.muv_uv_inspection_enabled = BoolProperty(
- name="UV Inspection Enabled",
- description="UV Inspection is enabled",
- default=False
- )
- scene.muv_uv_inspection_show = BoolProperty(
- name="UV Inspection Showed",
- description="UV Inspection is showed",
- default=False,
- get=get_func,
- set=set_func,
- update=update_func
- )
- scene.muv_uv_inspection_show_overlapped = BoolProperty(
- name="Overlapped",
- description="Show overlapped UVs",
- default=False
- )
- scene.muv_uv_inspection_show_flipped = BoolProperty(
- name="Flipped",
- description="Show flipped UVs",
- default=False
- )
- scene.muv_uv_inspection_show_mode = EnumProperty(
- name="Mode",
- description="Show mode",
- items=[
- ('PART', "Part", "Show only overlapped/flipped part"),
- ('FACE', "Face", "Show overlapped/flipped face")
- ],
- default='PART'
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_props.uv_inspection
- del scene.muv_uv_inspection_enabled
- del scene.muv_uv_inspection_show
- del scene.muv_uv_inspection_show_overlapped
- del scene.muv_uv_inspection_show_flipped
- del scene.muv_uv_inspection_show_mode
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVInspection_Render(bpy.types.Operator):
- """
- Operation class: Render UV Inspection
- No operation (only rendering)
- """
-
- bl_idname = "uv.muv_uv_inspection_operator_render"
- bl_description = "Render overlapped/flipped UVs"
- bl_label = "Overlapped/Flipped UV renderer"
-
- __handle = None
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return False
- return impl.is_valid_context(context)
-
- @classmethod
- def is_running(cls, _):
- return 1 if cls.__handle else 0
-
- @classmethod
- def handle_add(cls, obj, context):
- sie = bpy.types.SpaceImageEditor
- cls.__handle = sie.draw_handler_add(
- MUV_OT_UVInspection_Render.draw, (obj, context),
- 'WINDOW', 'POST_PIXEL')
-
- @classmethod
- def handle_remove(cls):
- if cls.__handle is not None:
- bpy.types.SpaceImageEditor.draw_handler_remove(
- cls.__handle, 'WINDOW')
- cls.__handle = None
-
- @staticmethod
- def draw(_, context):
- sc = context.scene
- props = sc.muv_props.uv_inspection
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-
- if not MUV_OT_UVInspection_Render.is_running(context):
- return
-
- # OpenGL configuration
- bgl.glEnable(bgl.GL_BLEND)
-
- # render overlapped UV
- if sc.muv_uv_inspection_show_overlapped:
- color = prefs.uv_inspection_overlapped_color
- for info in props.overlapped_info:
- if sc.muv_uv_inspection_show_mode == 'PART':
- for poly in info["polygons"]:
- bgl.glBegin(bgl.GL_TRIANGLE_FAN)
- bgl.glColor4f(color[0], color[1], color[2], color[3])
- for uv in poly:
- x, y = context.region.view2d.view_to_region(
- uv.x, uv.y)
- bgl.glVertex2f(x, y)
- bgl.glEnd()
- elif sc.muv_uv_inspection_show_mode == 'FACE':
- bgl.glBegin(bgl.GL_TRIANGLE_FAN)
- bgl.glColor4f(color[0], color[1], color[2], color[3])
- for uv in info["subject_uvs"]:
- x, y = context.region.view2d.view_to_region(uv.x, uv.y)
- bgl.glVertex2f(x, y)
- bgl.glEnd()
-
- # render flipped UV
- if sc.muv_uv_inspection_show_flipped:
- color = prefs.uv_inspection_flipped_color
- for info in props.flipped_info:
- if sc.muv_uv_inspection_show_mode == 'PART':
- for poly in info["polygons"]:
- bgl.glBegin(bgl.GL_TRIANGLE_FAN)
- bgl.glColor4f(color[0], color[1], color[2], color[3])
- for uv in poly:
- x, y = context.region.view2d.view_to_region(
- uv.x, uv.y)
- bgl.glVertex2f(x, y)
- bgl.glEnd()
- elif sc.muv_uv_inspection_show_mode == 'FACE':
- bgl.glBegin(bgl.GL_TRIANGLE_FAN)
- bgl.glColor4f(color[0], color[1], color[2], color[3])
- for uv in info["uvs"]:
- x, y = context.region.view2d.view_to_region(uv.x, uv.y)
- bgl.glVertex2f(x, y)
- bgl.glEnd()
-
- def invoke(self, context, _):
- if not MUV_OT_UVInspection_Render.is_running(context):
- impl.update_uvinsp_info(context)
- MUV_OT_UVInspection_Render.handle_add(self, context)
- else:
- MUV_OT_UVInspection_Render.handle_remove()
-
- if context.area:
- context.area.tag_redraw()
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVInspection_Update(bpy.types.Operator):
- """
- Operation class: Update
- """
-
- bl_idname = "uv.muv_uv_inspection_operator_update"
- bl_label = "Update UV Inspection"
- bl_description = "Update UV Inspection"
- bl_options = {'REGISTER', 'UNDO'}
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- if not MUV_OT_UVInspection_Render.is_running(context):
- return False
- return impl.is_valid_context(context)
-
- def execute(self, context):
- impl.update_uvinsp_info(context)
-
- if context.area:
- context.area.tag_redraw()
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/uv_sculpt.py b/uv_magic_uv/legacy/op/uv_sculpt.py
deleted file mode 100644
index 47a850d8..00000000
--- a/uv_magic_uv/legacy/op/uv_sculpt.py
+++ /dev/null
@@ -1,450 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-from math import pi, cos, tan, sin
-
-import bpy
-from bpy.props import (
- BoolProperty,
- IntProperty,
- EnumProperty,
- FloatProperty,
-)
-import bmesh
-import bgl
-from mathutils import Vector
-from bpy_extras import view3d_utils
-from mathutils.bvhtree import BVHTree
-from mathutils.geometry import barycentric_transform
-
-from ... import common
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import uv_sculpt_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class _Properties:
- idname = "uv_sculpt"
-
- @classmethod
- def init_props(cls, scene):
- def get_func(_):
- return MUV_OT_UVSculpt.is_running(bpy.context)
-
- def set_func(_, __):
- pass
-
- def update_func(_, __):
- bpy.ops.uv.muv_uv_sculpt_operator('INVOKE_REGION_WIN')
-
- scene.muv_uv_sculpt_enabled = BoolProperty(
- name="UV Sculpt",
- description="UV Sculpt is enabled",
- default=False
- )
- scene.muv_uv_sculpt_enable = BoolProperty(
- name="UV Sculpt Showed",
- description="UV Sculpt is enabled",
- default=False,
- get=get_func,
- set=set_func,
- update=update_func
- )
- scene.muv_uv_sculpt_radius = IntProperty(
- name="Radius",
- description="Radius of the brush",
- min=1,
- max=500,
- default=30
- )
- scene.muv_uv_sculpt_strength = FloatProperty(
- name="Strength",
- description="How powerful the effect of the brush when applied",
- min=0.0,
- max=1.0,
- default=0.03,
- )
- scene.muv_uv_sculpt_tools = EnumProperty(
- name="Tools",
- description="Select Tools for the UV sculpt brushes",
- items=[
- ('GRAB', "Grab", "Grab UVs"),
- ('RELAX', "Relax", "Relax UVs"),
- ('PINCH', "Pinch", "Pinch UVs")
- ],
- default='GRAB'
- )
- scene.muv_uv_sculpt_show_brush = BoolProperty(
- name="Show Brush",
- description="Show Brush",
- default=True
- )
- scene.muv_uv_sculpt_pinch_invert = BoolProperty(
- name="Invert",
- description="Pinch UV to invert direction",
- default=False
- )
- scene.muv_uv_sculpt_relax_method = EnumProperty(
- name="Method",
- description="Algorithm used for relaxation",
- items=[
- ('HC', "HC", "Use HC method for relaxation"),
- ('LAPLACIAN', "Laplacian",
- "Use laplacian method for relaxation")
- ],
- default='HC'
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_uv_sculpt_enabled
- del scene.muv_uv_sculpt_enable
- del scene.muv_uv_sculpt_radius
- del scene.muv_uv_sculpt_strength
- del scene.muv_uv_sculpt_tools
- del scene.muv_uv_sculpt_show_brush
- del scene.muv_uv_sculpt_pinch_invert
- del scene.muv_uv_sculpt_relax_method
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVSculpt(bpy.types.Operator):
- """
- Operation class: UV Sculpt in View3D
- """
-
- bl_idname = "uv.muv_uv_sculpt_operator"
- bl_label = "UV Sculpt"
- bl_description = "UV Sculpt in View3D"
- bl_options = {'REGISTER'}
-
- __handle = None
- __timer = None
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return False
- return impl.is_valid_context(context)
-
- @classmethod
- def is_running(cls, _):
- return 1 if cls.__handle else 0
-
- @classmethod
- def handle_add(cls, obj, context):
- if not cls.__handle:
- sv = bpy.types.SpaceView3D
- cls.__handle = sv.draw_handler_add(cls.draw_brush, (obj, context),
- "WINDOW", "POST_PIXEL")
- if not cls.__timer:
- cls.__timer = context.window_manager.event_timer_add(
- 0.1, window=context.window)
- context.window_manager.modal_handler_add(obj)
-
- @classmethod
- def handle_remove(cls, context):
- if cls.__handle:
- sv = bpy.types.SpaceView3D
- sv.draw_handler_remove(cls.__handle, "WINDOW")
- cls.__handle = None
- if cls.__timer:
- context.window_manager.event_timer_remove(cls.__timer)
- cls.__timer = None
-
- @classmethod
- def draw_brush(cls, obj, context):
- sc = context.scene
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
-
- num_segment = 180
- theta = 2 * pi / num_segment
- fact_t = tan(theta)
- fact_r = cos(theta)
- color = prefs.uv_sculpt_brush_color
-
- bgl.glBegin(bgl.GL_LINE_STRIP)
- bgl.glColor4f(color[0], color[1], color[2], color[3])
- x = sc.muv_uv_sculpt_radius * cos(0.0)
- y = sc.muv_uv_sculpt_radius * sin(0.0)
- for _ in range(num_segment):
- bgl.glVertex2f(x + obj.current_mco.x, y + obj.current_mco.y)
- tx = -y
- ty = x
- x = x + tx * fact_t
- y = y + ty * fact_t
- x = x * fact_r
- y = y * fact_r
- bgl.glEnd()
-
- def __init__(self):
- self.__loop_info = []
- self.__stroking = False
- self.current_mco = Vector((0.0, 0.0))
- self.__initial_mco = Vector((0.0, 0.0))
-
- def __stroke_init(self, context, _):
- sc = context.scene
-
- self.__initial_mco = self.current_mco
-
- # get influenced UV
- obj = context.active_object
- world_mat = obj.matrix_world
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- _, region, space = common.get_space_legacy('VIEW_3D', 'WINDOW',
- 'VIEW_3D')
-
- self.__loop_info = []
- for f in bm.faces:
- if not f.select:
- continue
- for i, l in enumerate(f.loops):
- loc_2d = view3d_utils.location_3d_to_region_2d(
- region, space.region_3d, world_mat * l.vert.co)
- diff = loc_2d - self.__initial_mco
- if diff.length < sc.muv_uv_sculpt_radius:
- info = {
- "face_idx": f.index,
- "loop_idx": i,
- "initial_vco": l.vert.co.copy(),
- "initial_vco_2d": loc_2d,
- "initial_uv": l[uv_layer].uv.copy(),
- "strength": impl.get_strength(
- diff.length, sc.muv_uv_sculpt_radius,
- sc.muv_uv_sculpt_strength)
- }
- self.__loop_info.append(info)
-
- def __stroke_apply(self, context, _):
- sc = context.scene
- obj = context.active_object
- world_mat = obj.matrix_world
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- mco = self.current_mco
-
- if sc.muv_uv_sculpt_tools == 'GRAB':
- for info in self.__loop_info:
- diff_uv = (mco - self.__initial_mco) * info["strength"]
- l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
- l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
-
- elif sc.muv_uv_sculpt_tools == 'PINCH':
- _, region, space = common.get_space_legacy('VIEW_3D', 'WINDOW',
- 'VIEW_3D')
- loop_info = []
- for f in bm.faces:
- if not f.select:
- continue
- for i, l in enumerate(f.loops):
- loc_2d = view3d_utils.location_3d_to_region_2d(
- region, space.region_3d, world_mat * l.vert.co)
- diff = loc_2d - self.__initial_mco
- if diff.length < sc.muv_uv_sculpt_radius:
- info = {
- "face_idx": f.index,
- "loop_idx": i,
- "initial_vco": l.vert.co.copy(),
- "initial_vco_2d": loc_2d,
- "initial_uv": l[uv_layer].uv.copy(),
- "strength": impl.get_strength(
- diff.length, sc.muv_uv_sculpt_radius,
- sc.muv_uv_sculpt_strength)
- }
- loop_info.append(info)
-
- # mouse coordinate to UV coordinate
- ray_vec = view3d_utils.region_2d_to_vector_3d(region,
- space.region_3d, mco)
- ray_vec.normalize()
- ray_orig = view3d_utils.region_2d_to_origin_3d(region,
- space.region_3d,
- mco)
- ray_tgt = ray_orig + ray_vec * 1000000.0
- mwi = world_mat.inverted()
- ray_orig_obj = mwi * ray_orig
- ray_tgt_obj = mwi * ray_tgt
- ray_dir_obj = ray_tgt_obj - ray_orig_obj
- ray_dir_obj.normalize()
- tree = BVHTree.FromBMesh(bm)
- loc, _, fidx, _ = tree.ray_cast(ray_orig_obj, ray_dir_obj)
- if not loc:
- return
- loops = [l for l in bm.faces[fidx].loops]
- uvs = [Vector((l[uv_layer].uv.x, l[uv_layer].uv.y, 0.0))
- for l in loops]
- target_uv = barycentric_transform(
- loc, loops[0].vert.co, loops[1].vert.co, loops[2].vert.co,
- uvs[0], uvs[1], uvs[2])
- target_uv = Vector((target_uv.x, target_uv.y))
-
- # move to target UV coordinate
- for info in loop_info:
- l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
- if sc.muv_uv_sculpt_pinch_invert:
- diff_uv = (l[uv_layer].uv - target_uv) * info["strength"]
- else:
- diff_uv = (target_uv - l[uv_layer].uv) * info["strength"]
- l[uv_layer].uv = l[uv_layer].uv + diff_uv / 10.0
-
- elif sc.muv_uv_sculpt_tools == 'RELAX':
- _, region, space = common.get_space_legacy('VIEW_3D', 'WINDOW',
- 'VIEW_3D')
-
- # get vertex and loop relation
- vert_db = {}
- for f in bm.faces:
- for l in f.loops:
- if l.vert in vert_db:
- vert_db[l.vert]["loops"].append(l)
- else:
- vert_db[l.vert] = {"loops": [l]}
-
- # get relaxation information
- for k in vert_db.keys():
- d = vert_db[k]
- d["uv_sum"] = Vector((0.0, 0.0))
- d["uv_count"] = 0
-
- for l in d["loops"]:
- ln = l.link_loop_next
- lp = l.link_loop_prev
- d["uv_sum"] = d["uv_sum"] + ln[uv_layer].uv
- d["uv_sum"] = d["uv_sum"] + lp[uv_layer].uv
- d["uv_count"] = d["uv_count"] + 2
- d["uv_p"] = d["uv_sum"] / d["uv_count"]
- d["uv_b"] = d["uv_p"] - d["loops"][0][uv_layer].uv
- for k in vert_db.keys():
- d = vert_db[k]
- d["uv_sum_b"] = Vector((0.0, 0.0))
- for l in d["loops"]:
- ln = l.link_loop_next
- lp = l.link_loop_prev
- dn = vert_db[ln.vert]
- dp = vert_db[lp.vert]
- d["uv_sum_b"] = d["uv_sum_b"] + dn["uv_b"] + dp["uv_b"]
-
- # apply
- for f in bm.faces:
- if not f.select:
- continue
- for i, l in enumerate(f.loops):
- loc_2d = view3d_utils.location_3d_to_region_2d(
- region, space.region_3d, world_mat * l.vert.co)
- diff = loc_2d - self.__initial_mco
- if diff.length >= sc.muv_uv_sculpt_radius:
- continue
- db = vert_db[l.vert]
- strength = impl.get_strength(diff.length,
- sc.muv_uv_sculpt_radius,
- sc.muv_uv_sculpt_strength)
-
- base = (1.0 - strength) * l[uv_layer].uv
- if sc.muv_uv_sculpt_relax_method == 'HC':
- t = 0.5 * (db["uv_b"] + db["uv_sum_b"] / d["uv_count"])
- diff = strength * (db["uv_p"] - t)
- target_uv = base + diff
- elif sc.muv_uv_sculpt_relax_method == 'LAPLACIAN':
- diff = strength * db["uv_p"]
- target_uv = base + diff
- else:
- continue
-
- l[uv_layer].uv = target_uv
-
- bmesh.update_edit_mesh(obj.data)
-
- def __stroke_exit(self, context, _):
- sc = context.scene
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- uv_layer = bm.loops.layers.uv.verify()
- mco = self.current_mco
-
- if sc.muv_uv_sculpt_tools == 'GRAB':
- for info in self.__loop_info:
- diff_uv = (mco - self.__initial_mco) * info["strength"]
- l = bm.faces[info["face_idx"]].loops[info["loop_idx"]]
- l[uv_layer].uv = info["initial_uv"] + diff_uv / 100.0
-
- bmesh.update_edit_mesh(obj.data)
-
- def modal(self, context, event):
- if context.area:
- context.area.tag_redraw()
-
- if not MUV_OT_UVSculpt.is_running(context):
- MUV_OT_UVSculpt.handle_remove(context)
-
- return {'FINISHED'}
-
- self.current_mco = Vector((event.mouse_region_x, event.mouse_region_y))
-
- region_types = [
- 'HEADER',
- 'UI',
- 'TOOLS',
- 'TOOL_PROPS',
- ]
- if not common.mouse_on_area_legacy(event, 'VIEW_3D') or \
- common.mouse_on_regions_legacy(event, 'VIEW_3D', region_types):
- return {'PASS_THROUGH'}
-
- if event.type == 'LEFTMOUSE':
- if event.value == 'PRESS':
- if not self.__stroking:
- self.__stroke_init(context, event)
- self.__stroking = True
- elif event.value == 'RELEASE':
- if self.__stroking:
- self.__stroke_exit(context, event)
- self.__stroking = False
- return {'RUNNING_MODAL'}
- elif event.type == 'MOUSEMOVE':
- if self.__stroking:
- self.__stroke_apply(context, event)
- return {'RUNNING_MODAL'}
- elif event.type == 'TIMER':
- if self.__stroking:
- self.__stroke_apply(context, event)
- return {'RUNNING_MODAL'}
-
- return {'PASS_THROUGH'}
-
- def invoke(self, context, _):
- if context.area:
- context.area.tag_redraw()
-
- if MUV_OT_UVSculpt.is_running(context):
- MUV_OT_UVSculpt.handle_remove(context)
- else:
- MUV_OT_UVSculpt.handle_add(self, context)
-
- return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/legacy/op/uvw.py b/uv_magic_uv/legacy/op/uvw.py
deleted file mode 100644
index 56777b18..00000000
--- a/uv_magic_uv/legacy/op/uvw.py
+++ /dev/null
@@ -1,181 +0,0 @@
-# <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__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bmesh
-from bpy.props import (
- FloatProperty,
- FloatVectorProperty,
- BoolProperty
-)
-
-from ... import common
-from ...impl import uvw_impl as impl
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
- 'Properties',
- 'MUV_OT_UVW_BoxMap',
- 'MUV_OT_UVW_BestPlanerMap',
-]
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "uvw"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_uvw_enabled = BoolProperty(
- name="UVW Enabled",
- description="UVW is enabled",
- default=False
- )
- scene.muv_uvw_assign_uvmap = BoolProperty(
- name="Assign UVMap",
- description="Assign UVMap when no UVmaps are available",
- default=True
- )
-
- @classmethod
- def del_props(cls, scene):
- del scene.muv_uvw_enabled
- del scene.muv_uvw_assign_uvmap
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVW_BoxMap(bpy.types.Operator):
- bl_idname = "uv.muv_uvw_operator_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
- )
- assign_uvmap = BoolProperty(
- name="Assign UVMap",
- description="Assign UVMap when no UVmaps are available",
- default=True
- )
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return impl.is_valid_context(context)
-
- def execute(self, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- # get UV layer
- uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
- if not uv_layer:
- return {'CANCELLED'}
-
- impl.apply_box_map(bm, uv_layer, self.size, self.offset,
- self.rotation, self.tex_aspect)
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
- bl_idname = "uv.muv_uvw_operator_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
- )
- assign_uvmap = BoolProperty(
- name="Assign UVMap",
- description="Assign UVMap when no UVmaps are available",
- default=True
- )
-
- @classmethod
- def poll(cls, context):
- # we can not get area/space/region from console
- if common.is_console_mode():
- return True
- return impl.is_valid_context(context)
-
- def execute(self, context):
- obj = context.active_object
- bm = bmesh.from_edit_mesh(obj.data)
- if common.check_version(2, 73, 0) >= 0:
- bm.faces.ensure_lookup_table()
-
- # get UV layer
- uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
- if not uv_layer:
- return {'CANCELLED'}
-
- impl.apply_planer_map(bm, uv_layer, self.size, self.offset,
- self.rotation, self.tex_aspect)
-
- bmesh.update_edit_mesh(obj.data)
-
- return {'FINISHED'}
diff --git a/uv_magic_uv/legacy/op/world_scale_uv.py b/uv_magic_uv/legacy/op/world_scale_uv.py
deleted file mode 100644
index 4a6b2869..00000000
--- a/uv_magic_uv/legacy/op/world_scale_uv.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# <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__ = "McBuff, Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
- EnumProperty,
- FloatProperty,
- IntVectorProperty,
- BoolProperty,
-)
-
-from ...utils.bl_class_registry import BlClassRegistry
-from ...utils.property_class_registry import PropertyClassRegistry
-from ...impl import world_scale_uv_impl as impl
-
-
-@PropertyClassRegistry(legacy=True)
-class Properties:
- idname = "world_scale_uv"
-
- @classmethod
- def init_props(cls, scene):
- scene.muv_world_scale_uv_enabled = BoolProperty(
- name="World Scale UV Enabled",
- description="World Scale UV is enabled",
- default=False
- )
- scene.muv_world_scale_uv_src_mesh_area = FloatProperty(
- name="Mesh Area",
- description="Source Mesh Area",
- default=0.0,
- min=0.0
- )
- scene.muv_world_scale_uv_src_uv_area = FloatProperty(
- name="UV Area",
- description="Source UV Area",
- default=0.0,
- min=0.0
- )
- scene.muv_world_scale_uv_src_density = FloatProperty(
- name="Density",
- description="Source Texel Density",
- default=0.0,
- min=0.0
- )
- scene.muv_world_scale_uv_tgt_density = FloatProperty(
- name="Density",
- description="Target Texel Density",
- default=0.0,
- min=0.0
- )
- scene.muv_world_scale_uv_tgt_scaling_factor = FloatProperty(
- name="Scaling Factor",
- default=1.0,
- max=1000.0,
- min=0.00001
- )
- scene.muv_world_scale_uv_tgt_texture_size = IntVectorProperty(
- name="Texture Size",
- size=2,
- min=1,
- soft_max=10240,
- default=(1024, 1024),
- )
- scene.muv_world_scale_uv_mode = EnumProperty(
- name="Mode",
- description="Density calculation mode",
- items=[
- ('PROPORTIONAL_TO_MESH', "Proportional to Mesh",
- "Apply density proportionaled by mesh size"),
- ('SCALING_DENSITY', "Scaling Density",
- "Apply scaled density from source"),
- ('SAME_DENSITY', "Same Density",
- "Apply same density of source"),
- ('MANUAL', "Manual", "Specify density and size by manual"),
- ],
- default='MANUAL'
- )
- scene.muv_world_scale_uv_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 del_props(cls, scene):
- del scene.muv_world_scale_uv_enabled
- del scene.muv_world_scale_uv_src_mesh_area
- del scene.muv_world_scale_uv_src_uv_area
- del scene.muv_world_scale_uv_src_density
- del scene.muv_world_scale_uv_tgt_density
- del scene.muv_world_scale_uv_tgt_scaling_factor
- del scene.muv_world_scale_uv_mode
- del scene.muv_world_scale_uv_origin
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_Measure(bpy.types.Operator):
- """
- Operation class: Measure face size
- """
-
- bl_idname = "uv.muv_world_scale_uv_operator_measure"
- bl_label = "Measure World Scale UV"
- bl_description = "Measure face size for scale calculation"
- bl_options = {'REGISTER', 'UNDO'}
-
- def __init__(self):
- self.__impl = impl.MeasureImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.MeasureImpl.poll(context)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
- """
- Operation class: Apply scaled UV (Manual)
- """
-
- bl_idname = "uv.muv_world_scale_uv_operator_apply_manual"
- bl_label = "Apply World Scale UV (Manual)"
- bl_description = "Apply scaled UV based on user specification"
- bl_options = {'REGISTER', 'UNDO'}
-
- tgt_density = FloatProperty(
- name="Density",
- description="Target Texel Density",
- default=1.0,
- min=0.0
- )
- tgt_texture_size = IntVectorProperty(
- name="Texture Size",
- size=2,
- min=1,
- soft_max=10240,
- default=(1024, 1024),
- )
- 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'
- )
- show_dialog = BoolProperty(
- name="Show Diaglog Menu",
- description="Show dialog menu if true",
- default=True,
- options={'HIDDEN', 'SKIP_SAVE'}
- )
-
- def __init__(self):
- self.__impl = impl.ApplyManualImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.ApplyManualImpl.poll(context)
-
- def draw(self, context):
- self.__impl.draw(self, context)
-
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
- """
- Operation class: Apply scaled UV (Scaling Density)
- """
-
- bl_idname = "uv.muv_world_scale_uv_operator_apply_scaling_density"
- bl_label = "Apply World Scale UV (Scaling Density)"
- bl_description = "Apply scaled UV with scaling density"
- bl_options = {'REGISTER', 'UNDO'}
-
- tgt_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'
- )
- src_density = FloatProperty(
- name="Density",
- description="Source Texel Density",
- default=0.0,
- min=0.0,
- options={'HIDDEN'}
- )
- same_density = BoolProperty(
- name="Same Density",
- description="Apply same density",
- default=False,
- options={'HIDDEN'}
- )
- show_dialog = BoolProperty(
- name="Show Diaglog Menu",
- description="Show dialog menu if true",
- default=True,
- options={'HIDDEN', 'SKIP_SAVE'}
- )
-
- def __init__(self):
- self.__impl = impl.ApplyScalingDensityImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.ApplyScalingDensityImpl.poll(context)
-
- def draw(self, context):
- self.__impl.draw(self, context)
-
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
- """
- Operation class: Apply scaled UV (Proportional to mesh)
- """
-
- bl_idname = "uv.muv_world_scale_uv_operator_apply_proportional_to_mesh"
- bl_label = "Apply World Scale UV (Proportional to mesh)"
- bl_description = "Apply scaled UV proportionaled to mesh"
- bl_options = {'REGISTER', 'UNDO'}
-
- 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'
- )
- src_density = FloatProperty(
- name="Source Density",
- description="Source Texel Density",
- default=0.0,
- min=0.0,
- options={'HIDDEN'}
- )
- src_uv_area = FloatProperty(
- name="Source UV Area",
- description="Source UV Area",
- default=0.0,
- min=0.0,
- options={'HIDDEN'}
- )
- src_mesh_area = FloatProperty(
- name="Source Mesh Area",
- description="Source Mesh Area",
- default=0.0,
- min=0.0,
- options={'HIDDEN'}
- )
- show_dialog = BoolProperty(
- name="Show Diaglog Menu",
- description="Show dialog menu if true",
- default=True,
- options={'HIDDEN', 'SKIP_SAVE'}
- )
-
- def __init__(self):
- self.__impl = impl.ApplyProportionalToMeshImpl()
-
- @classmethod
- def poll(cls, context):
- return impl.ApplyProportionalToMeshImpl.poll(context)
-
- def draw(self, context):
- self.__impl.draw(self, context)
-
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
-
- def execute(self, context):
- return self.__impl.execute(self, context)
diff --git a/uv_magic_uv/legacy/preferences.py b/uv_magic_uv/legacy/preferences.py
deleted file mode 100644
index e21f1753..00000000
--- a/uv_magic_uv/legacy/preferences.py
+++ /dev/null
@@ -1,518 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-from bpy.props import (
- FloatProperty,
- FloatVectorProperty,
- BoolProperty,
- EnumProperty,
- IntProperty,
- StringProperty,
-)
-from bpy.types import AddonPreferences
-
-from . import op
-from . import ui
-from ..utils.bl_class_registry import BlClassRegistry
-from ..utils.addon_updator import AddonUpdatorManager
-
-__all__ = [
- 'add_builtin_menu',
- 'remove_builtin_menu',
- 'Preferences'
-]
-
-
-def view3d_uvmap_menu_fn(self, context):
- layout = self.layout
- sc = context.scene
-
- layout.separator()
- layout.label(text="Copy/Paste UV", icon='IMAGE_COL')
- # Copy/Paste UV
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_CopyPasteUV.bl_idname,
- text="Copy/Paste UV")
- # Transfer UV
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TransferUV.bl_idname,
- text="Transfer UV")
-
- layout.separator()
- layout.label("UV Manipulation", icon='IMAGE_COL')
- # Flip/Rotate UV
- ops = layout.operator(op.flip_rotate_uv.MUV_OT_FlipRotate.bl_idname,
- text="Flip/Rotate UV")
- ops.seams = sc.muv_flip_rotate_uv_seams
- # Mirror UV
- ops = layout.operator(op.mirror_uv.MUV_OT_MirrorUV.bl_idname,
- text="Mirror UV")
- ops.axis = sc.muv_mirror_uv_axis
- # Move UV
- layout.operator(op.move_uv.MUV_OT_MoveUV.bl_idname, text="Move UV")
- # World Scale UV
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_WorldScaleUV.bl_idname,
- text="World Scale UV")
- # Preserve UV
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_PreserveUVAspect.bl_idname,
- text="Preserve UV")
- # Texture Lock
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TextureLock.bl_idname,
- text="Texture Lock")
- # Texture Wrap
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TextureWrap.bl_idname,
- text="Texture Wrap")
- # UV Sculpt
- layout.prop(sc, "muv_uv_sculpt_enable", text="UV Sculpt")
-
- layout.separator()
- layout.label("UV Mapping", icon='IMAGE_COL')
- # Unwrap Constraint
- ops = layout.operator(
- op.unwrap_constraint.MUV_OT_UnwrapConstraint.bl_idname,
- text="Unwrap Constraint")
- ops.u_const = sc.muv_unwrap_constraint_u_const
- ops.v_const = sc.muv_unwrap_constraint_v_const
- # Texture Projection
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_TextureProjection.bl_idname,
- text="Texture Projection")
- # UVW
- layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_UVW.bl_idname, text="UVW")
-
-
-def view3d_object_menu_fn(self, _):
- layout = self.layout
-
- layout.separator()
- # Copy/Paste UV (Among Objecct)
- layout.menu(ui.VIEW3D_MT_object.MUV_MT_CopyPasteUV_Object.bl_idname,
- text="Copy/Paste UV")
- layout.label("Copy/Paste UV", icon='IMAGE_COL')
-
-
-def image_uvs_menu_fn(self, context):
- layout = self.layout
- sc = context.scene
-
- layout.separator()
- # Align UV Cursor
- layout.menu(ui.IMAGE_MT_uvs.MUV_MT_AlignUVCursor.bl_idname,
- text="Align UV Cursor")
- # UV Bounding Box
- layout.prop(sc, "muv_uv_bounding_box_show", text="UV Bounding Box")
- # UV Inspection
- layout.menu(ui.IMAGE_MT_uvs.MUV_MT_UVInspection.bl_idname,
- text="UV Inspection")
- layout.label("Editor Enhancement", icon='IMAGE_COL')
-
- layout.separator()
- # Align UV
- layout.menu(ui.IMAGE_MT_uvs.MUV_MT_AlignUV.bl_idname, text="Align UV")
- # Smooth UV
- ops = layout.operator(op.smooth_uv.MUV_OT_SmoothUV.bl_idname,
- text="Smooth")
- ops.transmission = sc.muv_smooth_uv_transmission
- ops.select = sc.muv_smooth_uv_select
- ops.mesh_infl = sc.muv_smooth_uv_mesh_infl
- # Select UV
- layout.menu(ui.IMAGE_MT_uvs.MUV_MT_SelectUV.bl_idname, text="Select UV")
- # Pack UV
- ops = layout.operator(op.pack_uv.MUV_OT_PackUV.bl_idname, text="Pack UV")
- ops.allowable_center_deviation = sc.muv_pack_uv_allowable_center_deviation
- ops.allowable_size_deviation = sc.muv_pack_uv_allowable_size_deviation
- layout.label("UV Manipulation", icon='IMAGE_COL')
-
- layout.separator()
- # Copy/Paste UV (on UV/Image Editor)
- layout.menu(ui.IMAGE_MT_uvs.MUV_MT_CopyPasteUV_UVEdit.bl_idname,
- text="Copy/Paste UV")
- layout.label("Copy/Paste UV", icon='IMAGE_COL')
-
-
-def add_builtin_menu():
- bpy.types.VIEW3D_MT_uv_map.append(view3d_uvmap_menu_fn)
- bpy.types.VIEW3D_MT_object.append(view3d_object_menu_fn)
- bpy.types.IMAGE_MT_uvs.append(image_uvs_menu_fn)
-
-
-def remove_builtin_menu():
- bpy.types.IMAGE_MT_uvs.remove(image_uvs_menu_fn)
- bpy.types.VIEW3D_MT_uv_map.remove(view3d_uvmap_menu_fn)
- bpy.types.VIEW3D_MT_object.remove(view3d_object_menu_fn)
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_CheckAddonUpdate(bpy.types.Operator):
- bl_idname = "uv.muv_check_addon_update"
- bl_label = "Check Update"
- bl_description = "Check Add-on Update"
- bl_options = {'REGISTER', 'UNDO'}
-
- def execute(self, context):
- updater = AddonUpdatorManager.get_instance()
- updater.check_update_candidate()
-
- return {'FINISHED'}
-
-
-@BlClassRegistry(legacy=True)
-class MUV_OT_UpdateAddon(bpy.types.Operator):
- bl_idname = "uv.muv_update_addon"
- bl_label = "Update"
- bl_description = "Update Add-on"
- bl_options = {'REGISTER', 'UNDO'}
-
- branch_name = StringProperty(
- name="Branch Name",
- description="Branch name to update",
- default="",
- )
-
- def execute(self, context):
- updater = AddonUpdatorManager.get_instance()
- updater.update(self.branch_name)
-
- return {'FINISHED'}
-
-
-def get_update_candidate_branches(_, __):
- updater = AddonUpdatorManager.get_instance()
- if not updater.candidate_checked():
- return []
-
- return [(name, name, "") for name in updater.get_candidate_branch_names()]
-
-
-@BlClassRegistry(legacy=True)
-class Preferences(AddonPreferences):
- """Preferences class: Preferences for this add-on"""
-
- bl_idname = "uv_magic_uv"
-
- def update_enable_builtin_menu(self, _):
- if self['enable_builtin_menu']:
- add_builtin_menu()
- else:
- remove_builtin_menu()
-
- # enable to add features to built-in menu
- enable_builtin_menu = BoolProperty(
- name="Built-in Menu",
- description="Enable built-in menu",
- default=True,
- update=update_enable_builtin_menu
- )
-
- # for UV Sculpt
- uv_sculpt_brush_color = FloatVectorProperty(
- name="Color",
- description="Color",
- default=(1.0, 0.4, 0.4, 1.0),
- min=0.0,
- max=1.0,
- size=4,
- subtype='COLOR'
- )
-
- # for Overlapped UV
- uv_inspection_overlapped_color = FloatVectorProperty(
- name="Color",
- description="Color",
- default=(0.0, 0.0, 1.0, 0.3),
- min=0.0,
- max=1.0,
- size=4,
- subtype='COLOR'
- )
-
- # for Flipped UV
- uv_inspection_flipped_color = FloatVectorProperty(
- name="Color",
- description="Color",
- default=(1.0, 0.0, 0.0, 0.3),
- min=0.0,
- max=1.0,
- size=4,
- subtype='COLOR'
- )
-
- # for Texture Projection
- texture_projection_canvas_padding = FloatVectorProperty(
- name="Canvas Padding",
- description="Canvas Padding",
- size=2,
- max=50.0,
- min=0.0,
- default=(20.0, 20.0))
-
- # for UV Bounding Box
- uv_bounding_box_cp_size = FloatProperty(
- name="Size",
- description="Control Point Size",
- default=6.0,
- min=3.0,
- max=100.0)
- uv_bounding_box_cp_react_size = FloatProperty(
- name="React Size",
- description="Size event fired",
- default=10.0,
- min=3.0,
- max=100.0)
-
- # for UI
- category = EnumProperty(
- name="Category",
- description="Preferences Category",
- items=[
- ('INFO', "Information", "Information about this add-on"),
- ('CONFIG', "Configuration", "Configuration about this add-on"),
- ('UPDATE', "Update", "Update this add-on"),
- ],
- default='INFO'
- )
- info_desc_expanded = BoolProperty(
- name="Description",
- description="Description",
- default=False
- )
- info_loc_expanded = BoolProperty(
- name="Location",
- description="Location",
- default=False
- )
- conf_uv_sculpt_expanded = BoolProperty(
- name="UV Sculpt",
- description="UV Sculpt",
- default=False
- )
- conf_uv_inspection_expanded = BoolProperty(
- name="UV Inspection",
- description="UV Inspection",
- default=False
- )
- conf_texture_projection_expanded = BoolProperty(
- name="Texture Projection",
- description="Texture Projection",
- default=False
- )
- conf_uv_bounding_box_expanded = BoolProperty(
- name="UV Bounding Box",
- description="UV Bounding Box",
- default=False
- )
-
- # for add-on updater
- auto_check_update = BoolProperty(
- name="Auto-check for Update",
- description="If enabled, auto-check for updates using an interval",
- default=False
- )
- updater_intrval_months = IntProperty(
- name='Months',
- description="Number of months between checking for updates",
- default=0,
- min=0
- )
- updater_intrval_days = IntProperty(
- name='Days',
- description="Number of days between checking for updates",
- default=7,
- min=0
- )
- updater_intrval_hours = IntProperty(
- name='Hours',
- description="Number of hours between checking for updates",
- default=0,
- min=0,
- max=23
- )
- updater_intrval_minutes = IntProperty(
- name='Minutes',
- description="Number of minutes between checking for updates",
- default=0,
- min=0,
- max=59
- )
-
- # for add-on updater
- updater_branch_to_update = EnumProperty(
- name="branch",
- description="Target branch to update add-on",
- items=get_update_candidate_branches
- )
-
- def draw(self, context):
- layout = self.layout
-
- layout.row().prop(self, "category", expand=True)
-
- if self.category == 'INFO':
- layout.prop(
- self, "info_desc_expanded", text="Description",
- icon='DISCLOSURE_TRI_DOWN' if self.info_desc_expanded
- else 'DISCLOSURE_TRI_RIGHT')
- if self.info_desc_expanded:
- column = layout.column(align=True)
- column.label("Magic UV is composed of many UV editing" +
- " features.")
- column.label("See tutorial page if you are new to this" +
- " add-on.")
- column.label("https://github.com/nutti/Magic-UV/wiki/Tutorial")
-
- layout.prop(
- self, "info_loc_expanded", text="Location",
- icon='DISCLOSURE_TRI_DOWN' if self.info_loc_expanded
- else 'DISCLOSURE_TRI_RIGHT')
- if self.info_loc_expanded:
- row = layout.row(align=True)
- sp = row.split(percentage=0.5)
- sp.label("3D View > Tool shelf > Copy/Paste UV (Object mode)")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("Copy/Paste UV (Among objects)")
-
- row = layout.row(align=True)
- sp = row.split(percentage=0.5)
- sp.label("3D View > Tool shelf > Copy/Paste UV (Edit mode)")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("Copy/Paste UV (Among faces in 3D View)")
- col.label("Transfer UV")
-
- row = layout.row(align=True)
- sp = row.split(percentage=0.5)
- sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("Flip/Rotate UV")
- col.label("Mirror UV")
- col.label("Move UV")
- col.label("World Scale UV")
- col.label("Preserve UV Aspect")
- col.label("Texture Lock")
- col.label("Texture Wrap")
- col.label("UV Sculpt")
-
- row = layout.row(align=True)
- sp = row.split(percentage=0.5)
- sp.label("3D View > Tool shelf > UV Manipulation (Edit mode)")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("Unwrap Constraint")
- col.label("Texture Projection")
- col.label("UVW")
-
- row = layout.row(align=True)
- sp = row.split(percentage=0.5)
- sp.label("UV/Image Editor > Tool shelf > Copy/Paste UV")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("Copy/Paste UV (Among faces in UV/Image Editor)")
-
- row = layout.row(align=True)
- sp = row.split(percentage=0.5)
- sp.label("UV/Image Editor > Tool shelf > UV Manipulation")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("Align UV")
- col.label("Smooth UV")
- col.label("Select UV")
- col.label("Pack UV (Extension)")
-
- row = layout.row(align=True)
- sp = row.split(percentage=0.5)
- sp.label("UV/Image Editor > Tool shelf > Editor Enhancement")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("Align UV Cursor")
- col.label("UV Cursor Location")
- col.label("UV Bounding Box")
- col.label("UV Inspection")
-
- elif self.category == 'CONFIG':
- layout.prop(self, "enable_builtin_menu", text="Built-in Menu")
-
- layout.separator()
-
- layout.prop(
- self, "conf_uv_sculpt_expanded", text="UV Sculpt",
- icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_sculpt_expanded
- else 'DISCLOSURE_TRI_RIGHT')
- if self.conf_uv_sculpt_expanded:
- sp = layout.split(percentage=0.05)
- col = sp.column() # spacer
- sp = sp.split(percentage=0.3)
- col = sp.column()
- col.label("Brush Color:")
- col.prop(self, "uv_sculpt_brush_color", text="")
- layout.separator()
-
- layout.prop(
- self, "conf_uv_inspection_expanded", text="UV Inspection",
- icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_inspection_expanded
- else 'DISCLOSURE_TRI_RIGHT')
- if self.conf_uv_inspection_expanded:
- sp = layout.split(percentage=0.05)
- col = sp.column() # spacer
- sp = sp.split(percentage=0.3)
- col = sp.column()
- col.label("Overlapped UV Color:")
- col.prop(self, "uv_inspection_overlapped_color", text="")
- sp = sp.split(percentage=0.45)
- col = sp.column()
- col.label("Flipped UV Color:")
- col.prop(self, "uv_inspection_flipped_color", text="")
- layout.separator()
-
- layout.prop(
- self, "conf_texture_projection_expanded",
- text="Texture Projection",
- icon='DISCLOSURE_TRI_DOWN'
- if self.conf_texture_projection_expanded
- else 'DISCLOSURE_TRI_RIGHT')
- if self.conf_texture_projection_expanded:
- sp = layout.split(percentage=0.05)
- col = sp.column() # spacer
- sp = sp.split(percentage=0.3)
- col = sp.column()
- col.prop(self, "texture_projection_canvas_padding")
- layout.separator()
-
- layout.prop(
- self, "conf_uv_bounding_box_expanded", text="UV Bounding Box",
- icon='DISCLOSURE_TRI_DOWN'
- if self.conf_uv_bounding_box_expanded
- else 'DISCLOSURE_TRI_RIGHT')
- if self.conf_uv_bounding_box_expanded:
- sp = layout.split(percentage=0.05)
- col = sp.column() # spacer
- sp = sp.split(percentage=0.3)
- col = sp.column()
- col.label("Control Point:")
- col.prop(self, "uv_bounding_box_cp_size")
- col.prop(self, "uv_bounding_box_cp_react_size")
- layout.separator()
-
- elif self.category == 'UPDATE':
- addon_updater_ops.update_settings_ui(self, context)
diff --git a/uv_magic_uv/legacy/properites.py b/uv_magic_uv/legacy/properites.py
deleted file mode 100644
index b64a48f3..00000000
--- a/uv_magic_uv/legacy/properites.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-
-from ..utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
- 'MUV_Properties',
- 'init_props',
- 'clear_props',
-]
-
-
-# Properties used in this add-on.
-# pylint: disable=W0612
-class MUV_Properties():
- def __init__(self):
- self.prefs = MUV_Prefs()
-
-
-class MUV_Prefs():
- expanded = {
- "info_desc": False,
- "info_loc": False,
- "conf_uvsculpt": False,
- "conf_uvinsp": False,
- "conf_texproj": False,
- "conf_uvbb": False
- }
-
-
-def init_props(scene):
- scene.muv_props = MUV_Properties()
- PropertyClassRegistry.init_props(scene)
-
-
-def clear_props(scene):
- PropertyClassRegistry.del_props(scene)
- del scene.muv_props
diff --git a/uv_magic_uv/legacy/ui/IMAGE_MT_uvs.py b/uv_magic_uv/legacy/ui/IMAGE_MT_uvs.py
deleted file mode 100644
index bf071bf5..00000000
--- a/uv_magic_uv/legacy/ui/IMAGE_MT_uvs.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
- align_uv_cursor,
- copy_paste_uv_uvedit,
- align_uv,
- select_uv,
- uv_inspection
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_MT_CopyPasteUV_UVEdit',
- 'MUV_MT_AlignUV',
- 'MUV_MT_SelectUV',
- 'MUV_MT_AlignUVCursor',
- 'MUV_MT_UVInspection',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_UVEdit(bpy.types.Menu):
- """
- Menu class: Master menu of Copy/Paste UV coordinate on UV/ImageEditor
- """
-
- bl_idname = "uv.muv_copy_paste_uv_uvedit_menu"
- bl_label = "Copy/Paste UV"
- bl_description = "Copy and Paste UV coordinate among object"
-
- def draw(self, _):
- layout = self.layout
-
- layout.operator(
- copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_CopyUV.bl_idname,
- text="Copy")
- layout.operator(
- copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_PasteUV.bl_idname,
- text="Paste")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_AlignUV(bpy.types.Menu):
- """
- Menu class: Master menu of Align UV
- """
-
- bl_idname = "uv.muv_align_uv_menu"
- bl_label = "Align UV"
- bl_description = "Align UV"
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- ops = layout.operator(align_uv.MUV_OT_AlignUV_Circle.bl_idname,
- text="Circle")
- ops.transmission = sc.muv_align_uv_transmission
- ops.select = sc.muv_align_uv_select
-
- ops = layout.operator(align_uv.MUV_OT_AlignUV_Straighten.bl_idname,
- text="Straighten")
- ops.transmission = sc.muv_align_uv_transmission
- ops.select = sc.muv_align_uv_select
- ops.vertical = sc.muv_align_uv_vertical
- ops.horizontal = sc.muv_align_uv_horizontal
-
- ops = layout.operator(align_uv.MUV_OT_AlignUV_Axis.bl_idname,
- text="XY-axis")
- ops.transmission = sc.muv_align_uv_transmission
- ops.select = sc.muv_align_uv_select
- ops.vertical = sc.muv_align_uv_vertical
- ops.horizontal = sc.muv_align_uv_horizontal
- ops.location = sc.muv_align_uv_location
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_SelectUV(bpy.types.Menu):
- """
- Menu class: Master menu of Select UV
- """
-
- bl_idname = "uv.muv_select_uv_menu"
- bl_label = "Select UV"
- bl_description = "Select UV"
-
- def draw(self, _):
- layout = self.layout
-
- layout.operator(select_uv.MUV_OT_SelectUV_SelectOverlapped.bl_idname,
- text="Overlapped")
- layout.operator(select_uv.MUV_OT_SelectUV_SelectFlipped.bl_idname,
- text="Flipped")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_AlignUVCursor(bpy.types.Menu):
- """
- Menu class: Master menu of Align UV Cursor
- """
-
- bl_idname = "uv.muv_align_uv_cursor_menu"
- bl_label = "Align UV Cursor"
- bl_description = "Align UV cursor"
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Left Top")
- ops.position = 'LEFT_TOP'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Middle Top")
- ops.position = 'MIDDLE_TOP'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Right Top")
- ops.position = 'RIGHT_TOP'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Left Middle")
- ops.position = 'LEFT_MIDDLE'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Center")
- ops.position = 'CENTER'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Right Middle")
- ops.position = 'RIGHT_MIDDLE'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Left Bottom")
- ops.position = 'LEFT_BOTTOM'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Middle Bottom")
- ops.position = 'MIDDLE_BOTTOM'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- ops = layout.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Right Bottom")
- ops.position = 'RIGHT_BOTTOM'
- ops.base = sc.muv_align_uv_cursor_align_method
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_UVInspection(bpy.types.Menu):
- """
- Menu class: Master menu of UV Inspection
- """
-
- bl_idname = "uv.muv_uv_inspection_menu"
- bl_label = "UV Inspection"
- bl_description = "UV Inspection"
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- layout.prop(sc, "muv_uv_inspection_show", text="UV Inspection")
- layout.operator(uv_inspection.MUV_OT_UVInspection_Update.bl_idname,
- text="Update")
diff --git a/uv_magic_uv/legacy/ui/VIEW3D_MT_object.py b/uv_magic_uv/legacy/ui/VIEW3D_MT_object.py
deleted file mode 100644
index e1c751ae..00000000
--- a/uv_magic_uv/legacy/ui/VIEW3D_MT_object.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import copy_paste_uv_object
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_MT_CopyPasteUV_Object',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV_Object(bpy.types.Menu):
- """
- Menu class: Master menu of Copy/Paste UV coordinate among object
- """
-
- bl_idname = "uv.muv_copy_paste_uv_object_menu"
- bl_label = "Copy/Paste UV"
- bl_description = "Copy and Paste UV coordinate among object"
-
- def draw(self, _):
- layout = self.layout
-
- layout.menu(
- copy_paste_uv_object.MUV_MT_CopyPasteUVObject_CopyUV.bl_idname,
- text="Copy")
- layout.menu(
- copy_paste_uv_object.MUV_MT_CopyPasteUVObject_PasteUV.bl_idname,
- text="Paste")
diff --git a/uv_magic_uv/legacy/ui/VIEW3D_MT_uv_map.py b/uv_magic_uv/legacy/ui/VIEW3D_MT_uv_map.py
deleted file mode 100644
index d229322a..00000000
--- a/uv_magic_uv/legacy/ui/VIEW3D_MT_uv_map.py
+++ /dev/null
@@ -1,257 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-import bpy.utils
-
-from ..op import (
- texture_lock,
- copy_paste_uv,
- preserve_uv_aspect,
- texture_projection,
- texture_wrap,
- transfer_uv,
- uvw,
- world_scale_uv
-)
-from ..op.world_scale_uv import MUV_OT_WorldScaleUV_ApplyProportionalToMesh
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_MT_CopyPasteUV',
- 'MUV_MT_TransferUV',
- 'MUV_MT_TextureLock',
- 'MUV_MT_WorldScaleUV',
- 'MUV_MT_TextureWrap',
- 'MUV_MT_UVW',
- 'MUV_MT_TextureProjection',
- 'MUV_MT_PreserveUVAspect',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_CopyPasteUV(bpy.types.Menu):
- """
- Menu class: Master menu of Copy/Paste UV coordinate
- """
-
- bl_idname = "uv.muv_copy_paste_uv_menu"
- bl_label = "Copy/Paste UV"
- bl_description = "Copy and Paste UV coordinate"
-
- def draw(self, _):
- layout = self.layout
-
- layout.label(text="Default")
- layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_CopyUV.bl_idname,
- text="Copy")
- layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_PasteUV.bl_idname,
- text="Paste")
-
- layout.separator()
-
- layout.label(text="Selection Sequence")
- layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqCopyUV.bl_idname,
- text="Copy")
- layout.menu(copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqPasteUV.bl_idname,
- text="Paste")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TransferUV(bpy.types.Menu):
- """
- Menu class: Master menu of Transfer UV coordinate
- """
-
- bl_idname = "uv.muv_transfer_uv_menu"
- bl_label = "Transfer UV"
- bl_description = "Transfer UV coordinate"
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- layout.operator(transfer_uv.MUV_OT_TransferUV_CopyUV.bl_idname,
- text="Copy")
- ops = layout.operator(transfer_uv.MUV_OT_TransferUV_PasteUV.bl_idname,
- text="Paste")
- ops.invert_normals = sc.muv_transfer_uv_invert_normals
- ops.copy_seams = sc.muv_transfer_uv_copy_seams
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TextureLock(bpy.types.Menu):
- """
- Menu class: Master menu of Texture Lock
- """
-
- bl_idname = "uv.muv_texture_lock_menu"
- bl_label = "Texture Lock"
- bl_description = "Lock texture when vertices of mesh (Preserve UV)"
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- layout.label("Normal Mode")
- layout.operator(
- texture_lock.MUV_OT_TextureLock_Lock.bl_idname,
- text="Lock"
- if not texture_lock.MUV_OT_TextureLock_Lock.is_ready(context)
- else "ReLock")
- ops = layout.operator(texture_lock.MUV_OT_TextureLock_Unlock.bl_idname,
- text="Unlock")
- ops.connect = sc.muv_texture_lock_connect
-
- layout.separator()
-
- layout.label("Interactive Mode")
- layout.prop(sc, "muv_texture_lock_lock", text="Lock")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_WorldScaleUV(bpy.types.Menu):
- """
- Menu class: Master menu of world scale UV
- """
-
- bl_idname = "uv.muv_world_scale_uv_menu"
- bl_label = "World Scale UV"
- bl_description = ""
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- layout.operator(world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
- text="Measure")
-
- layout.operator(
- world_scale_uv.MUV_OT_WorldScaleUV_ApplyManual.bl_idname,
- text="Apply (Manual)")
-
- ops = layout.operator(
- world_scale_uv.MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
- text="Apply (Same Desity)")
- ops.src_density = sc.muv_world_scale_uv_src_density
- ops.same_density = True
-
- ops = layout.operator(
- world_scale_uv.MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
- text="Apply (Scaling Desity)")
- ops.src_density = sc.muv_world_scale_uv_src_density
- ops.same_density = False
- ops.tgt_scaling_factor = sc.muv_world_scale_uv_tgt_scaling_factor
-
- ops = layout.operator(
- MUV_OT_WorldScaleUV_ApplyProportionalToMesh.bl_idname,
- text="Apply (Proportional to Mesh)")
- ops.src_density = sc.muv_world_scale_uv_src_density
- ops.src_uv_area = sc.muv_world_scale_uv_src_uv_area
- ops.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
- ops.origin = sc.muv_world_scale_uv_origin
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TextureWrap(bpy.types.Menu):
- """
- Menu class: Master menu of Texture Wrap
- """
-
- bl_idname = "uv.muv_texture_wrap_menu"
- bl_label = "Texture Wrap"
- bl_description = ""
-
- def draw(self, _):
- layout = self.layout
-
- layout.operator(texture_wrap.MUV_OT_TextureWrap_Refer.bl_idname,
- text="Refer")
- layout.operator(texture_wrap.MUV_OT_TextureWrap_Set.bl_idname,
- text="Set")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_UVW(bpy.types.Menu):
- """
- Menu class: Master menu of UVW
- """
-
- bl_idname = "uv.muv_uvw_menu"
- bl_label = "UVW"
- bl_description = ""
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- ops = layout.operator(uvw.MUV_OT_UVW_BoxMap.bl_idname, text="Box")
- ops.assign_uvmap = sc.muv_uvw_assign_uvmap
-
- ops = layout.operator(uvw.MUV_OT_UVW_BestPlanerMap.bl_idname,
- text="Best Planner")
- ops.assign_uvmap = sc.muv_uvw_assign_uvmap
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_TextureProjection(bpy.types.Menu):
- """
- Menu class: Master menu of Texture Projection
- """
-
- bl_idname = "uv.muv_texture_projection_menu"
- bl_label = "Texture Projection"
- bl_description = ""
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- layout.prop(sc, "muv_texture_projection_enable",
- text="Texture Projection")
- layout.operator(
- texture_projection.MUV_OT_TextureProjection_Project.bl_idname,
- text="Project")
-
-
-@BlClassRegistry(legacy=True)
-class MUV_MT_PreserveUVAspect(bpy.types.Menu):
- """
- Menu class: Master menu of Preserve UV Aspect
- """
-
- bl_idname = "uv.muv_preserve_uv_aspect_menu"
- bl_label = "Preserve UV Aspect"
- bl_description = ""
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- for key in bpy.data.images.keys():
- ops = layout.operator(
- preserve_uv_aspect.MUV_OT_PreserveUVAspect.bl_idname, text=key)
- ops.dest_img_name = key
- ops.origin = sc.muv_preserve_uv_aspect_origin
diff --git a/uv_magic_uv/legacy/ui/__init__.py b/uv_magic_uv/legacy/ui/__init__.py
deleted file mode 100644
index bf790a8e..00000000
--- a/uv_magic_uv/legacy/ui/__init__.py
+++ /dev/null
@@ -1,50 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-if "bpy" in locals():
- import importlib
- importlib.reload(view3d_copy_paste_uv_objectmode)
- importlib.reload(view3d_copy_paste_uv_editmode)
- importlib.reload(view3d_uv_manipulation)
- importlib.reload(view3d_uv_mapping)
- importlib.reload(uvedit_copy_paste_uv)
- importlib.reload(uvedit_uv_manipulation)
- importlib.reload(uvedit_editor_enhancement)
- importlib.reload(VIEW3D_MT_uv_map)
- importlib.reload(VIEW3D_MT_object)
- importlib.reload(IMAGE_MT_uvs)
-else:
- from . import view3d_copy_paste_uv_objectmode
- from . import view3d_copy_paste_uv_editmode
- from . import view3d_uv_manipulation
- from . import view3d_uv_mapping
- from . import uvedit_copy_paste_uv
- from . import uvedit_uv_manipulation
- from . import uvedit_editor_enhancement
- from . import VIEW3D_MT_uv_map
- from . import VIEW3D_MT_object
- from . import IMAGE_MT_uvs
-
-import bpy \ No newline at end of file
diff --git a/uv_magic_uv/legacy/ui/uvedit_copy_paste_uv.py b/uv_magic_uv/legacy/ui/uvedit_copy_paste_uv.py
deleted file mode 100644
index 9848f03b..00000000
--- a/uv_magic_uv/legacy/ui/uvedit_copy_paste_uv.py
+++ /dev/null
@@ -1,62 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import copy_paste_uv_uvedit
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_UVEdit_CopyPasteUV',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_UVEdit_CopyPasteUV(bpy.types.Panel):
- """
- Panel class: Copy/Paste UV on Property Panel on UV/ImageEditor
- """
-
- bl_space_type = 'IMAGE_EDITOR'
- bl_region_type = 'TOOLS'
- bl_label = "Copy/Paste UV"
- bl_category = "Magic UV"
- bl_context = 'mesh_edit'
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, _):
- layout = self.layout
- layout.label(text="", icon='IMAGE_COL')
-
- def draw(self, _):
- layout = self.layout
-
- row = layout.row(align=True)
- row.operator(
- copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_CopyUV.bl_idname,
- text="Copy")
- row.operator(
- copy_paste_uv_uvedit.MUV_OT_CopyPasteUVUVEdit_PasteUV.bl_idname,
- text="Paste")
diff --git a/uv_magic_uv/legacy/ui/uvedit_editor_enhancement.py b/uv_magic_uv/legacy/ui/uvedit_editor_enhancement.py
deleted file mode 100644
index 3f750feb..00000000
--- a/uv_magic_uv/legacy/ui/uvedit_editor_enhancement.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
- align_uv_cursor,
- uv_bounding_box,
- uv_inspection,
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_UVEdit_EditorEnhancement',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_UVEdit_EditorEnhancement(bpy.types.Panel):
- """
- Panel class: UV/Image Editor Enhancement
- """
-
- bl_space_type = 'IMAGE_EDITOR'
- bl_region_type = 'TOOLS'
- bl_label = "Editor Enhancement"
- bl_category = "Magic UV"
- bl_context = 'mesh_edit'
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, _):
- layout = self.layout
- layout.label(text="", icon='IMAGE_COL')
-
- def draw(self, context):
- layout = self.layout
- sc = context.scene
-
- box = layout.box()
- box.prop(sc, "muv_align_uv_cursor_enabled", text="Align UV Cursor")
- if sc.muv_align_uv_cursor_enabled:
- box.prop(sc, "muv_align_uv_cursor_align_method", expand=True)
-
- col = box.column(align=True)
-
- row = col.row(align=True)
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Left Top")
- ops.position = 'LEFT_TOP'
- ops.base = sc.muv_align_uv_cursor_align_method
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Middle Top")
- ops.position = 'MIDDLE_TOP'
- ops.base = sc.muv_align_uv_cursor_align_method
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Right Top")
- ops.position = 'RIGHT_TOP'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- row = col.row(align=True)
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Left Middle")
- ops.position = 'LEFT_MIDDLE'
- ops.base = sc.muv_align_uv_cursor_align_method
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Center")
- ops.position = 'CENTER'
- ops.base = sc.muv_align_uv_cursor_align_method
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Right Middle")
- ops.position = 'RIGHT_MIDDLE'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- row = col.row(align=True)
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Left Bottom")
- ops.position = 'LEFT_BOTTOM'
- ops.base = sc.muv_align_uv_cursor_align_method
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Middle Bottom")
- ops.position = 'MIDDLE_BOTTOM'
- ops.base = sc.muv_align_uv_cursor_align_method
- ops = row.operator(align_uv_cursor.MUV_OT_AlignUVCursor.bl_idname,
- text="Right Bottom")
- ops.position = 'RIGHT_BOTTOM'
- ops.base = sc.muv_align_uv_cursor_align_method
-
- box = layout.box()
- box.prop(sc, "muv_uv_cursor_location_enabled",
- text="UV Cursor Location")
- if sc.muv_uv_cursor_location_enabled:
- box.prop(sc, "muv_align_uv_cursor_cursor_loc", text="")
-
- box = layout.box()
- box.prop(sc, "muv_uv_bounding_box_enabled", text="UV Bounding Box")
- if sc.muv_uv_bounding_box_enabled:
- box.prop(
- sc, "muv_uv_bounding_box_show",
- text="Hide"
- if uv_bounding_box.MUV_OT_UVBoundingBox.is_running(context)
- else "Show",
- icon='RESTRICT_VIEW_OFF'
- if uv_bounding_box.MUV_OT_UVBoundingBox.is_running(context)
- else 'RESTRICT_VIEW_ON')
- box.prop(sc, "muv_uv_bounding_box_uniform_scaling",
- text="Uniform Scaling")
- box.prop(sc, "muv_uv_bounding_box_boundary", text="Boundary")
-
- box = layout.box()
- box.prop(sc, "muv_uv_inspection_enabled", text="UV Inspection")
- if sc.muv_uv_inspection_enabled:
- row = box.row()
- row.prop(
- sc, "muv_uv_inspection_show",
- text="Hide"
- if uv_inspection.MUV_OT_UVInspection_Render.is_running(context)
- else "Show",
- icon='RESTRICT_VIEW_OFF'
- if uv_inspection.MUV_OT_UVInspection_Render.is_running(context)
- else 'RESTRICT_VIEW_ON')
- row.operator(uv_inspection.MUV_OT_UVInspection_Update.bl_idname,
- text="Update")
- row = box.row()
- row.prop(sc, "muv_uv_inspection_show_overlapped")
- row.prop(sc, "muv_uv_inspection_show_flipped")
- row = box.row()
- row.prop(sc, "muv_uv_inspection_show_mode")
diff --git a/uv_magic_uv/legacy/ui/uvedit_uv_manipulation.py b/uv_magic_uv/legacy/ui/uvedit_uv_manipulation.py
deleted file mode 100644
index 96cf17d3..00000000
--- a/uv_magic_uv/legacy/ui/uvedit_uv_manipulation.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
- align_uv,
- smooth_uv,
- pack_uv,
- select_uv,
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_UVEdit_UVManipulation',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_UVEdit_UVManipulation(bpy.types.Panel):
- """
- Panel class: UV Manipulation on Property Panel on UV/ImageEditor
- """
-
- bl_space_type = 'IMAGE_EDITOR'
- bl_region_type = 'TOOLS'
- bl_label = "UV Manipulation"
- bl_category = "Magic UV"
- bl_context = 'mesh_edit'
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, _):
- layout = self.layout
- layout.label(text="", icon='IMAGE_COL')
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
-
- box = layout.box()
- box.prop(sc, "muv_align_uv_enabled", text="Align UV")
- if sc.muv_align_uv_enabled:
- col = box.column()
- row = col.row(align=True)
- ops = row.operator(align_uv.MUV_OT_AlignUV_Circle.bl_idname,
- text="Circle")
- ops.transmission = sc.muv_align_uv_transmission
- ops.select = sc.muv_align_uv_select
- ops = row.operator(align_uv.MUV_OT_AlignUV_Straighten.bl_idname,
- text="Straighten")
- ops.transmission = sc.muv_align_uv_transmission
- ops.select = sc.muv_align_uv_select
- ops.vertical = sc.muv_align_uv_vertical
- ops.horizontal = sc.muv_align_uv_horizontal
- ops.mesh_infl = sc.muv_align_uv_mesh_infl
- row = col.row()
- ops = row.operator(align_uv.MUV_OT_AlignUV_Axis.bl_idname,
- text="XY-axis")
- ops.transmission = sc.muv_align_uv_transmission
- ops.select = sc.muv_align_uv_select
- ops.vertical = sc.muv_align_uv_vertical
- ops.horizontal = sc.muv_align_uv_horizontal
- ops.location = sc.muv_align_uv_location
- ops.mesh_infl = sc.muv_align_uv_mesh_infl
- row.prop(sc, "muv_align_uv_location", text="")
-
- col = box.column(align=True)
- row = col.row(align=True)
- row.prop(sc, "muv_align_uv_transmission", text="Transmission")
- row.prop(sc, "muv_align_uv_select", text="Select")
- row = col.row(align=True)
- row.prop(sc, "muv_align_uv_vertical", text="Vertical")
- row.prop(sc, "muv_align_uv_horizontal", text="Horizontal")
- col.prop(sc, "muv_align_uv_mesh_infl", text="Mesh Influence")
-
- box = layout.box()
- box.prop(sc, "muv_smooth_uv_enabled", text="Smooth UV")
- if sc.muv_smooth_uv_enabled:
- ops = box.operator(smooth_uv.MUV_OT_SmoothUV.bl_idname,
- text="Smooth")
- ops.transmission = sc.muv_smooth_uv_transmission
- ops.select = sc.muv_smooth_uv_select
- ops.mesh_infl = sc.muv_smooth_uv_mesh_infl
- col = box.column(align=True)
- row = col.row(align=True)
- row.prop(sc, "muv_smooth_uv_transmission", text="Transmission")
- row.prop(sc, "muv_smooth_uv_select", text="Select")
- col.prop(sc, "muv_smooth_uv_mesh_infl", text="Mesh Influence")
-
- box = layout.box()
- box.prop(sc, "muv_select_uv_enabled", text="Select UV")
- if sc.muv_select_uv_enabled:
- row = box.row(align=True)
- row.operator(select_uv.MUV_OT_SelectUV_SelectOverlapped.bl_idname)
- row.operator(select_uv.MUV_OT_SelectUV_SelectFlipped.bl_idname)
-
- box = layout.box()
- box.prop(sc, "muv_pack_uv_enabled", text="Pack UV (Extension)")
- if sc.muv_pack_uv_enabled:
- ops = box.operator(pack_uv.MUV_OT_PackUV.bl_idname, text="Pack UV")
- ops.allowable_center_deviation = \
- sc.muv_pack_uv_allowable_center_deviation
- ops.allowable_size_deviation = \
- sc.muv_pack_uv_allowable_size_deviation
- box.label("Allowable Center Deviation:")
- box.prop(sc, "muv_pack_uv_allowable_center_deviation", text="")
- box.label("Allowable Size Deviation:")
- box.prop(sc, "muv_pack_uv_allowable_size_deviation", text="")
diff --git a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_editmode.py b/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_editmode.py
deleted file mode 100644
index ee2713b2..00000000
--- a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_editmode.py
+++ /dev/null
@@ -1,93 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
- transfer_uv,
- copy_paste_uv,
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_View3D_Edit_CopyPasteUV',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_Edit_CopyPasteUV(bpy.types.Panel):
- """
- Panel class: Copy/Paste UV on Property Panel on View3D
- """
-
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'TOOLS'
- bl_label = "Copy/Paste UV"
- bl_category = "Magic UV"
- bl_context = 'mesh_edit'
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, _):
- layout = self.layout
- layout.label(text="", icon='IMAGE_COL')
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
-
- box = layout.box()
- box.prop(sc, "muv_copy_paste_uv_enabled", text="Copy/Paste UV")
- if sc.muv_copy_paste_uv_enabled:
- row = box.row(align=True)
- if sc.muv_copy_paste_uv_mode == 'DEFAULT':
- row.menu(copy_paste_uv.MUV_MT_CopyPasteUV_CopyUV.bl_idname,
- text="Copy")
- row.menu(copy_paste_uv.MUV_MT_CopyPasteUV_PasteUV.bl_idname,
- text="Paste")
- elif sc.muv_copy_paste_uv_mode == 'SEL_SEQ':
- row.menu(
- copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqCopyUV.bl_idname,
- text="Copy")
- row.menu(
- copy_paste_uv.MUV_MT_CopyPasteUV_SelSeqPasteUV.bl_idname,
- text="Paste")
- box.prop(sc, "muv_copy_paste_uv_mode", expand=True)
- box.prop(sc, "muv_copy_paste_uv_copy_seams", text="Seams")
- box.prop(sc, "muv_copy_paste_uv_strategy", text="Strategy")
-
- box = layout.box()
- box.prop(sc, "muv_transfer_uv_enabled", text="Transfer UV")
- if sc.muv_transfer_uv_enabled:
- row = box.row(align=True)
- row.operator(transfer_uv.MUV_OT_TransferUV_CopyUV.bl_idname,
- text="Copy")
- ops = row.operator(transfer_uv.MUV_OT_TransferUV_PasteUV.bl_idname,
- text="Paste")
- ops.invert_normals = sc.muv_transfer_uv_invert_normals
- ops.copy_seams = sc.muv_transfer_uv_copy_seams
- row = box.row()
- row.prop(sc, "muv_transfer_uv_invert_normals",
- text="Invert Normals")
- row.prop(sc, "muv_transfer_uv_copy_seams", text="Seams")
diff --git a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_objectmode.py b/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_objectmode.py
deleted file mode 100644
index 58031b0f..00000000
--- a/uv_magic_uv/legacy/ui/view3d_copy_paste_uv_objectmode.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import copy_paste_uv_object
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_View3D_Object_CopyPasteUV',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_Object_CopyPasteUV(bpy.types.Panel):
- """
- Panel class: Copy/Paste UV on Property Panel on View3D
- """
-
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'TOOLS'
- bl_label = "Copy/Paste UV"
- bl_category = "Magic UV"
- bl_context = 'objectmode'
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, _):
- layout = self.layout
- layout.label(text="", icon='IMAGE_COL')
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
-
- row = layout.row(align=True)
- row.menu(
- copy_paste_uv_object.MUV_MT_CopyPasteUVObject_CopyUV.bl_idname,
- text="Copy")
- row.menu(
- copy_paste_uv_object.MUV_MT_CopyPasteUVObject_PasteUV.bl_idname,
- text="Paste")
- layout.prop(sc, "muv_copy_paste_uv_object_copy_seams",
- text="Seams")
diff --git a/uv_magic_uv/legacy/ui/view3d_uv_manipulation.py b/uv_magic_uv/legacy/ui/view3d_uv_manipulation.py
deleted file mode 100644
index 7d828a38..00000000
--- a/uv_magic_uv/legacy/ui/view3d_uv_manipulation.py
+++ /dev/null
@@ -1,289 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
- move_uv,
- flip_rotate_uv,
- mirror_uv,
- preserve_uv_aspect,
- texture_lock,
- texture_wrap,
- uv_sculpt,
- world_scale_uv,
-)
-from ..op.world_scale_uv import (
- MUV_OT_WorldScaleUV_ApplyProportionalToMesh,
- MUV_OT_WorldScaleUV_ApplyScalingDensity
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_View3D_UVManipulation',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
- """
- Panel class: UV Manipulation on Property Panel on View3D
- """
-
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'TOOLS'
- bl_label = "UV Manipulation"
- bl_category = "Magic UV"
- bl_context = 'mesh_edit'
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, _):
- layout = self.layout
- layout.label(text="", icon='IMAGE_COL')
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
-
- box = layout.box()
- box.prop(sc, "muv_flip_rotate_uv_enabled", text="Flip/Rotate UV")
- if sc.muv_flip_rotate_uv_enabled:
- row = box.row()
- ops = row.operator(flip_rotate_uv.MUV_OT_FlipRotate.bl_idname,
- text="Flip/Rotate")
- ops.seams = sc.muv_flip_rotate_uv_seams
- row.prop(sc, "muv_flip_rotate_uv_seams", text="Seams")
-
- box = layout.box()
- box.prop(sc, "muv_mirror_uv_enabled", text="Mirror UV")
- if sc.muv_mirror_uv_enabled:
- row = box.row()
- ops = row.operator(mirror_uv.MUV_OT_MirrorUV.bl_idname,
- text="Mirror")
- ops.axis = sc.muv_mirror_uv_axis
- row.prop(sc, "muv_mirror_uv_axis", text="")
-
- box = layout.box()
- box.prop(sc, "muv_move_uv_enabled", text="Move UV")
- if sc.muv_move_uv_enabled:
- col = box.column()
- if not move_uv.MUV_OT_MoveUV.is_running(context):
- col.operator(move_uv.MUV_OT_MoveUV.bl_idname, icon='PLAY',
- text="Start")
- else:
- col.operator(move_uv.MUV_OT_MoveUV.bl_idname, icon='PAUSE',
- text="Stop")
-
- box = layout.box()
- box.prop(sc, "muv_world_scale_uv_enabled", text="World Scale UV")
- if sc.muv_world_scale_uv_enabled:
- box.prop(sc, "muv_world_scale_uv_mode", text="")
-
- if sc.muv_world_scale_uv_mode == 'MANUAL':
- sp = box.split(percentage=0.5)
- col = sp.column()
- col.prop(sc, "muv_world_scale_uv_tgt_texture_size",
- text="Texture Size")
- sp = sp.split(percentage=1.0)
- col = sp.column()
- col.label("Density:")
- col.prop(sc, "muv_world_scale_uv_tgt_density", text="")
- box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
- ops = box.operator(
- world_scale_uv.MUV_OT_WorldScaleUV_ApplyManual.bl_idname,
- text="Apply")
- ops.tgt_density = sc.muv_world_scale_uv_tgt_density
- ops.tgt_texture_size = sc.muv_world_scale_uv_tgt_texture_size
- ops.origin = sc.muv_world_scale_uv_origin
- ops.show_dialog = False
-
- elif sc.muv_world_scale_uv_mode == 'SAME_DENSITY':
- sp = box.split(percentage=0.4)
- col = sp.column(align=True)
- col.label("Source:")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.operator(
- world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
- text="Measure")
-
- sp = box.split(percentage=0.7)
- col = sp.column(align=True)
- col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
- col.enabled = False
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("px2/cm2")
-
- box.separator()
- box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
- ops = box.operator(
- MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
- text="Apply")
- ops.src_density = sc.muv_world_scale_uv_src_density
- ops.origin = sc.muv_world_scale_uv_origin
- ops.same_density = True
- ops.show_dialog = False
-
- elif sc.muv_world_scale_uv_mode == 'SCALING_DENSITY':
- sp = box.split(percentage=0.4)
- col = sp.column(align=True)
- col.label("Source:")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.operator(
- world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
- text="Measure")
-
- sp = box.split(percentage=0.7)
- col = sp.column(align=True)
- col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
- col.enabled = False
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("px2/cm2")
-
- box.separator()
- box.prop(sc, "muv_world_scale_uv_tgt_scaling_factor",
- text="Scaling Factor")
- box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
- ops = box.operator(
- MUV_OT_WorldScaleUV_ApplyScalingDensity.bl_idname,
- text="Apply")
- ops.src_density = sc.muv_world_scale_uv_src_density
- ops.origin = sc.muv_world_scale_uv_origin
- ops.same_density = False
- ops.show_dialog = False
- ops.tgt_scaling_factor = \
- sc.muv_world_scale_uv_tgt_scaling_factor
-
- elif sc.muv_world_scale_uv_mode == 'PROPORTIONAL_TO_MESH':
- sp = box.split(percentage=0.4)
- col = sp.column(align=True)
- col.label("Source:")
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.operator(
- world_scale_uv.MUV_OT_WorldScaleUV_Measure.bl_idname,
- text="Measure")
-
- sp = box.split(percentage=0.7)
- col = sp.column(align=True)
- col.prop(sc, "muv_world_scale_uv_src_mesh_area",
- text="Mesh Area")
- col.prop(sc, "muv_world_scale_uv_src_uv_area", text="UV Area")
- col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
- col.enabled = False
- sp = sp.split(percentage=1.0)
- col = sp.column(align=True)
- col.label("cm2")
- col.label("px2")
- col.label("px2/cm2")
- col.enabled = False
-
- box.separator()
- box.prop(sc, "muv_world_scale_uv_origin", text="Origin")
- ops = box.operator(
- MUV_OT_WorldScaleUV_ApplyProportionalToMesh.bl_idname,
- text="Apply")
- ops.src_density = sc.muv_world_scale_uv_src_density
- ops.src_uv_area = sc.muv_world_scale_uv_src_uv_area
- ops.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
- ops.origin = sc.muv_world_scale_uv_origin
- ops.show_dialog = False
-
- box = layout.box()
- box.prop(sc, "muv_preserve_uv_aspect_enabled",
- text="Preserve UV Aspect")
- if sc.muv_preserve_uv_aspect_enabled:
- row = box.row()
- ops = row.operator(
- preserve_uv_aspect.MUV_OT_PreserveUVAspect.bl_idname,
- text="Change Image")
- ops.dest_img_name = sc.muv_preserve_uv_aspect_tex_image
- ops.origin = sc.muv_preserve_uv_aspect_origin
- row.prop(sc, "muv_preserve_uv_aspect_tex_image", text="")
- box.prop(sc, "muv_preserve_uv_aspect_origin", text="Origin")
-
- box = layout.box()
- box.prop(sc, "muv_texture_lock_enabled", text="Texture Lock")
- if sc.muv_texture_lock_enabled:
- row = box.row(align=True)
- col = row.column(align=True)
- col.label("Normal Mode:")
- col = row.column(align=True)
- col.operator(
- texture_lock.MUV_OT_TextureLock_Lock.bl_idname,
- text="Lock"
- if not texture_lock.MUV_OT_TextureLock_Lock.is_ready(context)
- else "ReLock")
- ops = col.operator(
- texture_lock.MUV_OT_TextureLock_Unlock.bl_idname,
- text="Unlock")
- ops.connect = sc.muv_texture_lock_connect
- col.prop(sc, "muv_texture_lock_connect", text="Connect")
-
- row = box.row(align=True)
- row.label("Interactive Mode:")
- box.prop(
- sc, "muv_texture_lock_lock",
- text="Unlock"
- if texture_lock.MUV_OT_TextureLock_Intr.is_running(context)
- else "Lock",
- icon='RESTRICT_VIEW_OFF'
- if texture_lock.MUV_OT_TextureLock_Intr.is_running(context)
- else 'RESTRICT_VIEW_ON')
-
- box = layout.box()
- box.prop(sc, "muv_texture_wrap_enabled", text="Texture Wrap")
- if sc.muv_texture_wrap_enabled:
- row = box.row(align=True)
- row.operator(texture_wrap.MUV_OT_TextureWrap_Refer.bl_idname,
- text="Refer")
- row.operator(texture_wrap.MUV_OT_TextureWrap_Set.bl_idname,
- text="Set")
- box.prop(sc, "muv_texture_wrap_set_and_refer")
- box.prop(sc, "muv_texture_wrap_selseq")
-
- box = layout.box()
- box.prop(sc, "muv_uv_sculpt_enabled", text="UV Sculpt")
- if sc.muv_uv_sculpt_enabled:
- box.prop(
- sc, "muv_uv_sculpt_enable",
- text="Disable"if uv_sculpt.MUV_OT_UVSculpt.is_running(context)
- else "Enable",
- icon='RESTRICT_VIEW_OFF'
- if uv_sculpt.MUV_OT_UVSculpt.is_running(context)
- else 'RESTRICT_VIEW_ON')
- col = box.column()
- col.label("Brush:")
- col.prop(sc, "muv_uv_sculpt_radius")
- col.prop(sc, "muv_uv_sculpt_strength")
- box.prop(sc, "muv_uv_sculpt_tools")
- if sc.muv_uv_sculpt_tools == 'PINCH':
- box.prop(sc, "muv_uv_sculpt_pinch_invert")
- elif sc.muv_uv_sculpt_tools == 'RELAX':
- box.prop(sc, "muv_uv_sculpt_relax_method")
- box.prop(sc, "muv_uv_sculpt_show_brush")
diff --git a/uv_magic_uv/legacy/ui/view3d_uv_mapping.py b/uv_magic_uv/legacy/ui/view3d_uv_mapping.py
deleted file mode 100644
index 3de86d0d..00000000
--- a/uv_magic_uv/legacy/ui/view3d_uv_mapping.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# <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__ = "Nutti <nutti.metro@gmail.com>"
-__status__ = "production"
-__version__ = "5.2"
-__date__ = "17 Nov 2018"
-
-import bpy
-
-from ..op import (
- uvw,
- texture_projection,
- unwrap_constraint,
-)
-from ..op.texture_projection import (
- MUV_OT_TextureProjection
-)
-from ...utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_View3D_UVMapping',
-]
-
-
-@BlClassRegistry(legacy=True)
-class MUV_PT_View3D_UVMapping(bpy.types.Panel):
- """
- Panel class: UV Mapping on Property Panel on View3D
- """
-
- bl_space_type = 'VIEW_3D'
- bl_region_type = 'TOOLS'
- bl_label = "UV Mapping"
- bl_category = "Magic UV"
- bl_context = 'mesh_edit'
- bl_options = {'DEFAULT_CLOSED'}
-
- def draw_header(self, _):
- layout = self.layout
- layout.label(text="", icon='IMAGE_COL')
-
- def draw(self, context):
- sc = context.scene
- layout = self.layout
-
- box = layout.box()
- box.prop(sc, "muv_unwrap_constraint_enabled", text="Unwrap Constraint")
- if sc.muv_unwrap_constraint_enabled:
- ops = box.operator(
- unwrap_constraint.MUV_OT_UnwrapConstraint.bl_idname,
- text="Unwrap")
- ops.u_const = sc.muv_unwrap_constraint_u_const
- ops.v_const = sc.muv_unwrap_constraint_v_const
- row = box.row(align=True)
- row.prop(sc, "muv_unwrap_constraint_u_const", text="U-Constraint")
- row.prop(sc, "muv_unwrap_constraint_v_const", text="V-Constraint")
-
- box = layout.box()
- box.prop(sc, "muv_texture_projection_enabled",
- text="Texture Projection")
- if sc.muv_texture_projection_enabled:
- row = box.row()
- row.prop(
- sc, "muv_texture_projection_enable",
- text="Disable"
- if MUV_OT_TextureProjection.is_running(context)
- else "Enable",
- icon='RESTRICT_VIEW_OFF'
- if MUV_OT_TextureProjection.is_running(context)
- else 'RESTRICT_VIEW_ON')
- row.prop(sc, "muv_texture_projection_tex_image", text="")
- box.prop(sc, "muv_texture_projection_tex_transparency",
- text="Transparency")
- col = box.column(align=True)
- row = col.row()
- row.prop(sc, "muv_texture_projection_adjust_window",
- text="Adjust Window")
- if not sc.muv_texture_projection_adjust_window:
- row.prop(sc, "muv_texture_projection_tex_magnitude",
- text="Magnitude")
- col.prop(sc, "muv_texture_projection_apply_tex_aspect",
- text="Texture Aspect Ratio")
- col.prop(sc, "muv_texture_projection_assign_uvmap",
- text="Assign UVMap")
- box.operator(
- texture_projection.MUV_OT_TextureProjection_Project.bl_idname,
- text="Project")
-
- box = layout.box()
- box.prop(sc, "muv_uvw_enabled", text="UVW")
- if sc.muv_uvw_enabled:
- row = box.row(align=True)
- ops = row.operator(uvw.MUV_OT_UVW_BoxMap.bl_idname, text="Box")
- ops.assign_uvmap = sc.muv_uvw_assign_uvmap
- ops = row.operator(uvw.MUV_OT_UVW_BestPlanerMap.bl_idname,
- text="Best Planner")
- ops.assign_uvmap = sc.muv_uvw_assign_uvmap
- box.prop(sc, "muv_uvw_assign_uvmap", text="Assign UVMap")
diff --git a/uv_magic_uv/lib/bglx.py b/uv_magic_uv/lib/bglx.py
index c4dadd69..72e030fa 100644
--- a/uv_magic_uv/lib/bglx.py
+++ b/uv_magic_uv/lib/bglx.py
@@ -1,10 +1,13 @@
from threading import Lock
+import bgl
+from bgl import Buffer as Buffer
import gpu
from gpu_extras.batch import batch_for_shader
GL_LINES = 0
GL_LINE_STRIP = 1
+GL_LINE_LOOP = 2
GL_TRIANGLES = 5
GL_TRIANGLE_FAN = 6
GL_QUADS = 4
@@ -18,7 +21,11 @@ class InternalData:
@classmethod
def __internal_new(cls):
- return super().__new__(cls)
+ inst = super().__new__(cls)
+ inst.color = [1.0, 1.0, 1.0, 1.0]
+ inst.line_width = 1.0
+
+ return inst
@classmethod
def get_instance(cls):
@@ -47,6 +54,9 @@ class InternalData:
def set_color(self, c):
self.color = c
+ def set_line_width(self, width):
+ self.line_width = width
+
def clear(self):
self.prim_mode = None
self.verts = []
@@ -65,14 +75,21 @@ class InternalData:
def get_color(self):
return self.color
+ def get_line_width(self):
+ return self.line_width
+
def get_tex_coords(self):
return self.tex_coords
-def glBegin(mode):
+def glLineWidth(width):
inst = InternalData.get_instance()
- inst.init()
- inst.set_prim_mode(mode)
+ inst.set_line_width(width)
+
+
+def glColor3f(r, g, b):
+ inst = InternalData.get_instance()
+ inst.set_color([r, g, b, 1.0])
def glColor4f(r, g, b, a):
@@ -80,6 +97,21 @@ def glColor4f(r, g, b, a):
inst.set_color([r, g, b, a])
+def glRecti(x0, y0, x1, y1):
+ glBegin(GL_QUADS)
+ glVertex2f(x0, y0)
+ glVertex2f(x0, y1)
+ glVertex2f(x1, y1)
+ glVertex2f(x1, y0)
+ glEnd()
+
+
+def glBegin(mode):
+ inst = InternalData.get_instance()
+ inst.init()
+ inst.set_prim_mode(mode)
+
+
def _get_transparency_shader():
vertex_shader = '''
uniform mat4 modelViewMatrix;
@@ -149,6 +181,11 @@ def glEnd():
elif inst.get_prim_mode() == GL_LINE_STRIP:
batch = batch_for_shader(shader, 'LINE_STRIP', data)
+
+ elif inst.get_prim_mode() == GL_LINE_LOOP:
+ data["pos"].append(data["pos"][0])
+ batch = batch_for_shader(shader, 'LINE_STRIP', data)
+
elif inst.get_prim_mode() == GL_TRIANGLES:
indices = []
for i in range(0, len(coords), 3):
@@ -189,3 +226,35 @@ def glVertex2f(x, y):
def glTexCoord2f(u, v):
inst = InternalData.get_instance()
inst.add_tex_coord([u, v])
+
+
+GL_BLEND = bgl.GL_BLEND
+GL_LINE_SMOOTH = bgl.GL_LINE_SMOOTH
+GL_INT = bgl.GL_INT
+GL_SCISSOR_BOX = bgl.GL_SCISSOR_BOX
+GL_TEXTURE_2D = bgl.GL_TEXTURE_2D
+GL_TEXTURE0 = bgl.GL_TEXTURE0
+
+
+def glEnable(cap):
+ bgl.glEnable(cap)
+
+
+def glDisable(cap):
+ bgl.glDisable(cap)
+
+
+def glScissor(x, y, width, height):
+ bgl.glScissor(x, y, width, height)
+
+
+def glGetIntegerv(pname, params):
+ bgl.glGetIntegerv(pname, params)
+
+
+def glActiveTexture(texture):
+ bgl.glActiveTexture(texture)
+
+
+def glBindTexture(target, texture):
+ bgl.glBindTexture(target, texture)
diff --git a/uv_magic_uv/op/align_uv.py b/uv_magic_uv/op/align_uv.py
index fbd119d2..8225858e 100644
--- a/uv_magic_uv/op/align_uv.py
+++ b/uv_magic_uv/op/align_uv.py
@@ -23,12 +23,271 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
+import math
+from math import atan2, tan, sin, cos
+
import bpy
from bpy.props import EnumProperty, BoolProperty, FloatProperty
+import bmesh
+from mathutils import Vector
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import align_uv_impl as impl
+from ..utils import compatibility as compat
+
+from .. import common
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
+
+
+# get sum vertex length of loop sequences
+def _get_loop_vert_len(loops):
+ length = 0
+ for l1, l2 in zip(loops[:-1], loops[1:]):
+ diff = l2.vert.co - l1.vert.co
+ length = length + abs(diff.length)
+
+ return length
+
+
+# get sum uv length of loop sequences
+def _get_loop_uv_len(loops, uv_layer):
+ length = 0
+ for l1, l2 in zip(loops[:-1], loops[1:]):
+ diff = l2[uv_layer].uv - l1[uv_layer].uv
+ length = length + abs(diff.length)
+
+ return length
+
+
+# get center/radius of circle by 3 vertices
+def _get_circle(v):
+ alpha = atan2((v[0].y - v[1].y), (v[0].x - v[1].x)) + math.pi / 2
+ beta = atan2((v[1].y - v[2].y), (v[1].x - v[2].x)) + math.pi / 2
+ ex = (v[0].x + v[1].x) / 2.0
+ ey = (v[0].y + v[1].y) / 2.0
+ fx = (v[1].x + v[2].x) / 2.0
+ fy = (v[1].y + v[2].y) / 2.0
+ cx = (ey - fy - ex * tan(alpha) + fx * tan(beta)) / \
+ (tan(beta) - tan(alpha))
+ cy = ey - (ex - cx) * tan(alpha)
+ center = Vector((cx, cy))
+
+ r = v[0] - center
+ radian = r.length
+
+ return center, radian
+
+
+# get position on circle with same arc length
+def _calc_v_on_circle(v, center, radius):
+ base = v[0]
+ theta = atan2(base.y - center.y, base.x - center.x)
+ new_v = []
+ for i in range(len(v)):
+ angle = theta + i * 2 * math.pi / len(v)
+ new_v.append(Vector((center.x + radius * sin(angle),
+ center.y + radius * cos(angle))))
+
+ return new_v
+
+
+# get accumulate vertex lengths of loop sequences
+def _get_loop_vert_accum_len(loops):
+ accum_lengths = [0.0]
+ length = 0
+ for l1, l2 in zip(loops[:-1], loops[1:]):
+ diff = l2.vert.co - l1.vert.co
+ length = length + abs(diff.length)
+ accum_lengths.extend([length])
+
+ return accum_lengths
+
+
+# get sum uv length of loop sequences
+def _get_loop_uv_accum_len(loops, uv_layer):
+ accum_lengths = [0.0]
+ length = 0
+ for l1, l2 in zip(loops[:-1], loops[1:]):
+ diff = l2[uv_layer].uv - l1[uv_layer].uv
+ length = length + abs(diff.length)
+ accum_lengths.extend([length])
+
+ return accum_lengths
+
+
+# get horizontal differential of UV influenced by mesh vertex
+def _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
+ common.debug_print(
+ "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
+
+ base_uv = loop_seqs[0][vidx][0][uv_layer].uv.copy()
+
+ # calculate original length
+ hloops = []
+ for s in loop_seqs:
+ hloops.extend([s[vidx][0], s[vidx][1]])
+ total_vlen = _get_loop_vert_len(hloops)
+ accum_vlens = _get_loop_vert_accum_len(hloops)
+ total_uvlen = _get_loop_uv_len(hloops, uv_layer)
+ accum_uvlens = _get_loop_uv_accum_len(hloops, uv_layer)
+ orig_uvs = [l[uv_layer].uv.copy() for l in hloops]
+
+ # calculate target length
+ tgt_noinfl = total_uvlen * (hidx + pidx) / len(loop_seqs)
+ tgt_infl = total_uvlen * accum_vlens[hidx * 2 + pidx] / total_vlen
+ target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
+ common.debug_print(target_length)
+ common.debug_print(accum_uvlens)
+
+ # calculate target UV
+ for i in range(len(accum_uvlens[:-1])):
+ # get line segment which UV will be placed
+ if ((accum_uvlens[i] <= target_length) and
+ (accum_uvlens[i + 1] > target_length)):
+ tgt_seg_len = target_length - accum_uvlens[i]
+ seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+ uv1 = orig_uvs[i]
+ uv2 = orig_uvs[i + 1]
+ target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+ break
+ elif i == (len(accum_uvlens[:-1]) - 1):
+ if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
+ raise Exception(
+ "Internal Error: horizontal_target_length={}"
+ " is not equal to {}"
+ .format(target_length, accum_uvlens[-1]))
+ tgt_seg_len = target_length - accum_uvlens[i]
+ seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+ uv1 = orig_uvs[i]
+ uv2 = orig_uvs[i + 1]
+ target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+ break
+ else:
+ raise Exception("Internal Error: horizontal_target_length={}"
+ " is not in range {} to {}"
+ .format(target_length, accum_uvlens[0],
+ accum_uvlens[-1]))
+
+ return target_uv
+
+
+# --------------------- LOOP STRUCTURE ----------------------
+#
+# loops[hidx][vidx][pidx]
+# hidx: horizontal index
+# vidx: vertical index
+# pidx: pair index
+#
+# <----- horizontal ----->
+#
+# (hidx, vidx, pidx) = (0, 3, 0)
+# | (hidx, vidx, pidx) = (1, 3, 0)
+# v v
+# ^ o --- oo --- o
+# | | || |
+# vertical | o --- oo --- o <- (hidx, vidx, pidx)
+# | o --- oo --- o = (1, 2, 1)
+# | | || |
+# v o --- oo --- o
+# ^ ^
+# | (hidx, vidx, pidx) = (1, 0, 1)
+# (hidx, vidx, pidx) = (0, 0, 0)
+#
+# -----------------------------------------------------------
+
+
+# get vertical differential of UV influenced by mesh vertex
+def _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, pidx, infl):
+ common.debug_print(
+ "loop_seqs[hidx={0}][vidx={1}][pidx={2}]".format(hidx, vidx, pidx))
+
+ base_uv = loop_seqs[hidx][0][pidx][uv_layer].uv.copy()
+
+ # calculate original length
+ vloops = []
+ for s in loop_seqs[hidx]:
+ vloops.append(s[pidx])
+ total_vlen = _get_loop_vert_len(vloops)
+ accum_vlens = _get_loop_vert_accum_len(vloops)
+ total_uvlen = _get_loop_uv_len(vloops, uv_layer)
+ accum_uvlens = _get_loop_uv_accum_len(vloops, uv_layer)
+ orig_uvs = [l[uv_layer].uv.copy() for l in vloops]
+
+ # calculate target length
+ tgt_noinfl = total_uvlen * int((vidx + 1) / 2) * 2 / len(loop_seqs[hidx])
+ tgt_infl = total_uvlen * accum_vlens[vidx] / total_vlen
+ target_length = tgt_noinfl * (1 - infl) + tgt_infl * infl
+ common.debug_print(target_length)
+ common.debug_print(accum_uvlens)
+
+ # calculate target UV
+ for i in range(len(accum_uvlens[:-1])):
+ # get line segment which UV will be placed
+ if ((accum_uvlens[i] <= target_length) and
+ (accum_uvlens[i + 1] > target_length)):
+ tgt_seg_len = target_length - accum_uvlens[i]
+ seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+ uv1 = orig_uvs[i]
+ uv2 = orig_uvs[i + 1]
+ target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+ break
+ elif i == (len(accum_uvlens[:-1]) - 1):
+ if abs(accum_uvlens[i + 1] - target_length) > 0.000001:
+ raise Exception("Internal Error: horizontal_target_length={}"
+ " is not equal to {}"
+ .format(target_length, accum_uvlens[-1]))
+ tgt_seg_len = target_length - accum_uvlens[i]
+ seg_len = accum_uvlens[i + 1] - accum_uvlens[i]
+ uv1 = orig_uvs[i]
+ uv2 = orig_uvs[i + 1]
+ target_uv = (uv1 - base_uv) + (uv2 - uv1) * tgt_seg_len / seg_len
+ break
+ else:
+ raise Exception("Internal Error: horizontal_target_length={}"
+ " is not in range {} to {}"
+ .format(target_length, accum_uvlens[0],
+ accum_uvlens[-1]))
+
+ return target_uv
+
+
+# get horizontal differential of UV no influenced
+def _get_hdiff_uv(uv_layer, loop_seqs, hidx):
+ base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+ h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
+
+ return hidx * h_uv / len(loop_seqs)
+
+
+# get vertical differential of UV no influenced
+def _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx):
+ base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+ v_uv = loop_seqs[0][-1][0][uv_layer].uv.copy() - base_uv
+
+ hseq = loop_seqs[hidx]
+ return int((vidx + 1) / 2) * v_uv / (len(hseq) / 2)
@PropertyClassRegistry()
@@ -94,6 +353,7 @@ class _Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_AlignUV_Circle(bpy.types.Operator):
bl_idname = "uv.muv_align_uv_operator_circle"
@@ -101,29 +361,85 @@ class MUV_OT_AlignUV_Circle(bpy.types.Operator):
bl_description = "Align UV coordinates to Circle"
bl_options = {'REGISTER', 'UNDO'}
- transmission: BoolProperty(
+ transmission = BoolProperty(
name="Transmission",
description="Align linked UVs",
default=False
)
- select: BoolProperty(
+ select = BoolProperty(
name="Select",
description="Select UVs which are aligned",
default=False
)
- def __init__(self):
- self.__impl = impl.CircleImpl()
-
@classmethod
def poll(cls, context):
- return impl.CircleImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ # loop_seqs[horizontal][vertical][loop]
+ loop_seqs, error = common.get_loop_sequences(bm, uv_layer, True)
+ if not loop_seqs:
+ self.report({'WARNING'}, error)
+ return {'CANCELLED'}
+
+ # get circle and new UVs
+ uvs = [hseq[0][0][uv_layer].uv.copy() for hseq in loop_seqs]
+ c, r = _get_circle(uvs[0:3])
+ new_uvs = _calc_v_on_circle(uvs, c, r)
+
+ # check center UV of circle
+ center = loop_seqs[0][-1][0].vert
+ for hseq in loop_seqs[1:]:
+ if len(hseq[-1]) != 1:
+ self.report({'WARNING'}, "Last face must be triangle")
+ return {'CANCELLED'}
+ if hseq[-1][0].vert != center:
+ self.report({'WARNING'}, "Center must be identical")
+ return {'CANCELLED'}
+
+ # align to circle
+ if self.transmission:
+ for hidx, hseq in enumerate(loop_seqs):
+ for vidx, pair in enumerate(hseq):
+ all_ = int((len(hseq) + 1) / 2)
+ r = (all_ - int((vidx + 1) / 2)) / all_
+ pair[0][uv_layer].uv = c + (new_uvs[hidx] - c) * r
+ if self.select:
+ pair[0][uv_layer].select = True
+
+ if len(pair) < 2:
+ continue
+ # for quad polygon
+ next_hidx = (hidx + 1) % len(loop_seqs)
+ pair[1][uv_layer].uv = c + ((new_uvs[next_hidx]) - c) * r
+ if self.select:
+ pair[1][uv_layer].select = True
+ else:
+ for hidx, hseq in enumerate(loop_seqs):
+ pair = hseq[0]
+ pair[0][uv_layer].uv = new_uvs[hidx]
+ pair[1][uv_layer].uv = new_uvs[(hidx + 1) % len(loop_seqs)]
+ if self.select:
+ pair[0][uv_layer].select = True
+ pair[1][uv_layer].select = True
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
bl_idname = "uv.muv_align_uv_operator_straighten"
@@ -131,29 +447,29 @@ class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
bl_description = "Straighten UV coordinates"
bl_options = {'REGISTER', 'UNDO'}
- transmission: BoolProperty(
+ transmission = BoolProperty(
name="Transmission",
description="Align linked UVs",
default=False
)
- select: BoolProperty(
+ select = BoolProperty(
name="Select",
description="Select UVs which are aligned",
default=False
)
- vertical: BoolProperty(
+ vertical = BoolProperty(
name="Vert-Infl (Vertical)",
description="Align vertical direction influenced "
"by mesh vertex proportion",
default=False
)
- horizontal: BoolProperty(
+ horizontal = BoolProperty(
name="Vert-Infl (Horizontal)",
description="Align horizontal direction influenced "
"by mesh vertex proportion",
default=False
)
- mesh_infl: FloatProperty(
+ mesh_infl = FloatProperty(
name="Mesh Influence",
description="Influence rate of mesh vertex",
min=0.0,
@@ -161,18 +477,121 @@ class MUV_OT_AlignUV_Straighten(bpy.types.Operator):
default=0.0
)
- def __init__(self):
- self.__impl = impl.StraightenImpl()
-
@classmethod
def poll(cls, context):
- return impl.StraightenImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
+
+ # selected and paralleled UV loop sequence will be aligned
+ def __align_w_transmission(self, loop_seqs, uv_layer):
+ base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+
+ # calculate diff UVs
+ diff_uvs = []
+ # hseq[vertical][loop]
+ for hidx, hseq in enumerate(loop_seqs):
+ # pair[loop]
+ diffs = []
+ for vidx in range(0, len(hseq), 2):
+ if self.horizontal:
+ hdiff_uvs = [
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+ self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+ self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 0, self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 1, self.mesh_infl),
+ ]
+ else:
+ hdiff_uvs = [
+ _get_hdiff_uv(uv_layer, loop_seqs, hidx),
+ _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1),
+ _get_hdiff_uv(uv_layer, loop_seqs, hidx),
+ _get_hdiff_uv(uv_layer, loop_seqs, hidx + 1)
+ ]
+ if self.vertical:
+ vdiff_uvs = [
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+ self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+ self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 0, self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 1, self.mesh_infl),
+ ]
+ else:
+ vdiff_uvs = [
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+ ]
+ diffs.append([hdiff_uvs, vdiff_uvs])
+ diff_uvs.append(diffs)
+
+ # update UV
+ for hseq, diffs in zip(loop_seqs, diff_uvs):
+ for vidx in range(0, len(hseq), 2):
+ loops = [
+ hseq[vidx][0], hseq[vidx][1],
+ hseq[vidx + 1][0], hseq[vidx + 1][1]
+ ]
+ for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+ diffs[int(vidx / 2)][1]):
+ l[uv_layer].uv = base_uv + hdiff + vdiff
+ if self.select:
+ l[uv_layer].select = True
+
+ # only selected UV loop sequence will be aligned
+ def __align_wo_transmission(self, loop_seqs, uv_layer):
+ base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+
+ h_uv = loop_seqs[-1][0][1][uv_layer].uv.copy() - base_uv
+ for hidx, hseq in enumerate(loop_seqs):
+ # only selected loop pair is targeted
+ pair = hseq[0]
+ hdiff_uv_0 = hidx * h_uv / len(loop_seqs)
+ hdiff_uv_1 = (hidx + 1) * h_uv / len(loop_seqs)
+ pair[0][uv_layer].uv = base_uv + hdiff_uv_0
+ pair[1][uv_layer].uv = base_uv + hdiff_uv_1
+ if self.select:
+ pair[0][uv_layer].select = True
+ pair[1][uv_layer].select = True
+
+ def __align(self, loop_seqs, uv_layer):
+ if self.transmission:
+ self.__align_w_transmission(loop_seqs, uv_layer)
+ else:
+ self.__align_wo_transmission(loop_seqs, uv_layer)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ # loop_seqs[horizontal][vertical][loop]
+ loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+ if not loop_seqs:
+ self.report({'WARNING'}, error)
+ return {'CANCELLED'}
+
+ # align
+ self.__align(loop_seqs, uv_layer)
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_AlignUV_Axis(bpy.types.Operator):
bl_idname = "uv.muv_align_uv_operator_axis"
@@ -180,29 +599,29 @@ class MUV_OT_AlignUV_Axis(bpy.types.Operator):
bl_description = "Align UV to XY-axis"
bl_options = {'REGISTER', 'UNDO'}
- transmission: BoolProperty(
+ transmission = BoolProperty(
name="Transmission",
description="Align linked UVs",
default=False
)
- select: BoolProperty(
+ select = BoolProperty(
name="Select",
description="Select UVs which are aligned",
default=False
)
- vertical: BoolProperty(
+ vertical = BoolProperty(
name="Vert-Infl (Vertical)",
description="Align vertical direction influenced "
"by mesh vertex proportion",
default=False
)
- horizontal: BoolProperty(
+ horizontal = BoolProperty(
name="Vert-Infl (Horizontal)",
description="Align horizontal direction influenced "
"by mesh vertex proportion",
default=False
)
- location: EnumProperty(
+ location = EnumProperty(
name="Location",
description="Align location",
items=[
@@ -212,7 +631,7 @@ class MUV_OT_AlignUV_Axis(bpy.types.Operator):
],
default='MIDDLE'
)
- mesh_infl: FloatProperty(
+ mesh_infl = FloatProperty(
name="Mesh Influence",
description="Influence rate of mesh vertex",
min=0.0,
@@ -220,12 +639,353 @@ class MUV_OT_AlignUV_Axis(bpy.types.Operator):
default=0.0
)
- def __init__(self):
- self.__impl = impl.AxisImpl()
-
@classmethod
def poll(cls, context):
- return impl.AxisImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
+
+ # get min/max of UV
+ def __get_uv_max_min(self, loop_seqs, uv_layer):
+ uv_max = Vector((-1000000.0, -1000000.0))
+ uv_min = Vector((1000000.0, 1000000.0))
+ for hseq in loop_seqs:
+ for l in hseq[0]:
+ uv = l[uv_layer].uv
+ uv_max.x = max(uv.x, uv_max.x)
+ uv_max.y = max(uv.y, uv_max.y)
+ uv_min.x = min(uv.x, uv_min.x)
+ uv_min.y = min(uv.y, uv_min.y)
+
+ return uv_max, uv_min
+
+ # get UV differentiation when UVs are aligned to X-axis
+ def __get_x_axis_align_diff_uvs(self, loop_seqs, uv_layer, uv_min,
+ width, height):
+ diff_uvs = []
+ for hidx, hseq in enumerate(loop_seqs):
+ pair = hseq[0]
+ luv0 = pair[0][uv_layer]
+ luv1 = pair[1][uv_layer]
+ target_uv0 = Vector((0.0, 0.0))
+ target_uv1 = Vector((0.0, 0.0))
+ if self.location == 'RIGHT_BOTTOM':
+ target_uv0.y = target_uv1.y = uv_min.y
+ elif self.location == 'MIDDLE':
+ target_uv0.y = target_uv1.y = uv_min.y + height * 0.5
+ elif self.location == 'LEFT_TOP':
+ target_uv0.y = target_uv1.y = uv_min.y + height
+ if luv0.uv.x < luv1.uv.x:
+ target_uv0.x = uv_min.x + hidx * width / len(loop_seqs)
+ target_uv1.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
+ else:
+ target_uv0.x = uv_min.x + (hidx + 1) * width / len(loop_seqs)
+ target_uv1.x = uv_min.x + hidx * width / len(loop_seqs)
+ diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
+
+ return diff_uvs
+
+ # get UV differentiation when UVs are aligned to Y-axis
+ def __get_y_axis_align_diff_uvs(self, loop_seqs, uv_layer, uv_min,
+ width, height):
+ diff_uvs = []
+ for hidx, hseq in enumerate(loop_seqs):
+ pair = hseq[0]
+ luv0 = pair[0][uv_layer]
+ luv1 = pair[1][uv_layer]
+ target_uv0 = Vector((0.0, 0.0))
+ target_uv1 = Vector((0.0, 0.0))
+ if self.location == 'RIGHT_BOTTOM':
+ target_uv0.x = target_uv1.x = uv_min.x + width
+ elif self.location == 'MIDDLE':
+ target_uv0.x = target_uv1.x = uv_min.x + width * 0.5
+ elif self.location == 'LEFT_TOP':
+ target_uv0.x = target_uv1.x = uv_min.x
+ if luv0.uv.y < luv1.uv.y:
+ target_uv0.y = uv_min.y + hidx * height / len(loop_seqs)
+ target_uv1.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
+ else:
+ target_uv0.y = uv_min.y + (hidx + 1) * height / len(loop_seqs)
+ target_uv1.y = uv_min.y + hidx * height / len(loop_seqs)
+ diff_uvs.append([target_uv0 - luv0.uv, target_uv1 - luv1.uv])
+
+ return diff_uvs
+
+ # only selected UV loop sequence will be aligned along to X-axis
+ def __align_to_x_axis_wo_transmission(self, loop_seqs, uv_layer,
+ uv_min, width, height):
+ # reverse if the UV coordinate is not sorted by position
+ need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
+ loop_seqs[-1][0][0][uv_layer].uv.x
+ if need_revese:
+ loop_seqs.reverse()
+ for hidx, hseq in enumerate(loop_seqs):
+ for vidx, pair in enumerate(hseq):
+ tmp = loop_seqs[hidx][vidx][0]
+ loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+ loop_seqs[hidx][vidx][1] = tmp
+
+ # get UV differential
+ diff_uvs = self.__get_x_axis_align_diff_uvs(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
+
+ # update UV
+ for hseq, duv in zip(loop_seqs, diff_uvs):
+ pair = hseq[0]
+ luv0 = pair[0][uv_layer]
+ luv1 = pair[1][uv_layer]
+ luv0.uv = luv0.uv + duv[0]
+ luv1.uv = luv1.uv + duv[1]
+
+ # only selected UV loop sequence will be aligned along to Y-axis
+ def __align_to_y_axis_wo_transmission(self, loop_seqs, uv_layer,
+ uv_min, width, height):
+ # reverse if the UV coordinate is not sorted by position
+ need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
+ loop_seqs[-1][0][0][uv_layer].uv.y
+ if need_revese:
+ loop_seqs.reverse()
+ for hidx, hseq in enumerate(loop_seqs):
+ for vidx, pair in enumerate(hseq):
+ tmp = loop_seqs[hidx][vidx][0]
+ loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+ loop_seqs[hidx][vidx][1] = tmp
+
+ # get UV differential
+ diff_uvs = self.__get_y_axis_align_diff_uvs(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
+
+ # update UV
+ for hseq, duv in zip(loop_seqs, diff_uvs):
+ pair = hseq[0]
+ luv0 = pair[0][uv_layer]
+ luv1 = pair[1][uv_layer]
+ luv0.uv = luv0.uv + duv[0]
+ luv1.uv = luv1.uv + duv[1]
+
+ # selected and paralleled UV loop sequence will be aligned along to X-axis
+ def __align_to_x_axis_w_transmission(self, loop_seqs, uv_layer,
+ uv_min, width, height):
+ # reverse if the UV coordinate is not sorted by position
+ need_revese = loop_seqs[0][0][0][uv_layer].uv.x > \
+ loop_seqs[-1][0][0][uv_layer].uv.x
+ if need_revese:
+ loop_seqs.reverse()
+ for hidx, hseq in enumerate(loop_seqs):
+ for vidx in range(len(hseq)):
+ tmp = loop_seqs[hidx][vidx][0]
+ loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+ loop_seqs[hidx][vidx][1] = tmp
+
+ # get offset UVs when the UVs are aligned to X-axis
+ align_diff_uvs = self.__get_x_axis_align_diff_uvs(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
+ base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+ offset_uvs = []
+ for hseq, aduv in zip(loop_seqs, align_diff_uvs):
+ luv0 = hseq[0][0][uv_layer]
+ luv1 = hseq[0][1][uv_layer]
+ offset_uvs.append([luv0.uv + aduv[0] - base_uv,
+ luv1.uv + aduv[1] - base_uv])
+
+ # get UV differential
+ diff_uvs = []
+ # hseq[vertical][loop]
+ for hidx, hseq in enumerate(loop_seqs):
+ # pair[loop]
+ diffs = []
+ for vidx in range(0, len(hseq), 2):
+ if self.horizontal:
+ hdiff_uvs = [
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+ self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+ self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 0, self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 1, self.mesh_infl),
+ ]
+ hdiff_uvs[0].y = hdiff_uvs[0].y + offset_uvs[hidx][0].y
+ hdiff_uvs[1].y = hdiff_uvs[1].y + offset_uvs[hidx][1].y
+ hdiff_uvs[2].y = hdiff_uvs[2].y + offset_uvs[hidx][0].y
+ hdiff_uvs[3].y = hdiff_uvs[3].y + offset_uvs[hidx][1].y
+ else:
+ hdiff_uvs = [
+ offset_uvs[hidx][0],
+ offset_uvs[hidx][1],
+ offset_uvs[hidx][0],
+ offset_uvs[hidx][1],
+ ]
+ if self.vertical:
+ vdiff_uvs = [
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+ self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+ self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 0, self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 1, self.mesh_infl),
+ ]
+ else:
+ vdiff_uvs = [
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+ ]
+ diffs.append([hdiff_uvs, vdiff_uvs])
+ diff_uvs.append(diffs)
+
+ # update UV
+ for hseq, diffs in zip(loop_seqs, diff_uvs):
+ for vidx in range(0, len(hseq), 2):
+ loops = [
+ hseq[vidx][0], hseq[vidx][1],
+ hseq[vidx + 1][0], hseq[vidx + 1][1]
+ ]
+ for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+ diffs[int(vidx / 2)][1]):
+ l[uv_layer].uv = base_uv + hdiff + vdiff
+ if self.select:
+ l[uv_layer].select = True
+
+ # selected and paralleled UV loop sequence will be aligned along to Y-axis
+ def __align_to_y_axis_w_transmission(self, loop_seqs, uv_layer,
+ uv_min, width, height):
+ # reverse if the UV coordinate is not sorted by position
+ need_revese = loop_seqs[0][0][0][uv_layer].uv.y > \
+ loop_seqs[-1][0][-1][uv_layer].uv.y
+ if need_revese:
+ loop_seqs.reverse()
+ for hidx, hseq in enumerate(loop_seqs):
+ for vidx in range(len(hseq)):
+ tmp = loop_seqs[hidx][vidx][0]
+ loop_seqs[hidx][vidx][0] = loop_seqs[hidx][vidx][1]
+ loop_seqs[hidx][vidx][1] = tmp
+
+ # get offset UVs when the UVs are aligned to Y-axis
+ align_diff_uvs = self.__get_y_axis_align_diff_uvs(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
+ base_uv = loop_seqs[0][0][0][uv_layer].uv.copy()
+ offset_uvs = []
+ for hseq, aduv in zip(loop_seqs, align_diff_uvs):
+ luv0 = hseq[0][0][uv_layer]
+ luv1 = hseq[0][1][uv_layer]
+ offset_uvs.append([luv0.uv + aduv[0] - base_uv,
+ luv1.uv + aduv[1] - base_uv])
+
+ # get UV differential
+ diff_uvs = []
+ # hseq[vertical][loop]
+ for hidx, hseq in enumerate(loop_seqs):
+ # pair[loop]
+ diffs = []
+ for vidx in range(0, len(hseq), 2):
+ if self.horizontal:
+ hdiff_uvs = [
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+ self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+ self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 0, self.mesh_infl),
+ _get_hdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 1, self.mesh_infl),
+ ]
+ hdiff_uvs[0].x = hdiff_uvs[0].x + offset_uvs[hidx][0].x
+ hdiff_uvs[1].x = hdiff_uvs[1].x + offset_uvs[hidx][1].x
+ hdiff_uvs[2].x = hdiff_uvs[2].x + offset_uvs[hidx][0].x
+ hdiff_uvs[3].x = hdiff_uvs[3].x + offset_uvs[hidx][1].x
+ else:
+ hdiff_uvs = [
+ offset_uvs[hidx][0],
+ offset_uvs[hidx][1],
+ offset_uvs[hidx][0],
+ offset_uvs[hidx][1],
+ ]
+ if self.vertical:
+ vdiff_uvs = [
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 0,
+ self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx, hidx, 1,
+ self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 0, self.mesh_infl),
+ _get_vdiff_uv_vinfl(uv_layer, loop_seqs, vidx + 1,
+ hidx, 1, self.mesh_infl),
+ ]
+ else:
+ vdiff_uvs = [
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx),
+ _get_vdiff_uv(uv_layer, loop_seqs, vidx + 1, hidx)
+ ]
+ diffs.append([hdiff_uvs, vdiff_uvs])
+ diff_uvs.append(diffs)
+
+ # update UV
+ for hseq, diffs in zip(loop_seqs, diff_uvs):
+ for vidx in range(0, len(hseq), 2):
+ loops = [
+ hseq[vidx][0], hseq[vidx][1],
+ hseq[vidx + 1][0], hseq[vidx + 1][1]
+ ]
+ for l, hdiff, vdiff in zip(loops, diffs[int(vidx / 2)][0],
+ diffs[int(vidx / 2)][1]):
+ l[uv_layer].uv = base_uv + hdiff + vdiff
+ if self.select:
+ l[uv_layer].select = True
+
+ def __align(self, loop_seqs, uv_layer, uv_min, width, height):
+ # align along to x-axis
+ if width > height:
+ if self.transmission:
+ self.__align_to_x_axis_w_transmission(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
+ else:
+ self.__align_to_x_axis_wo_transmission(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
+ # align along to y-axis
+ else:
+ if self.transmission:
+ self.__align_to_y_axis_w_transmission(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
+ else:
+ self.__align_to_y_axis_wo_transmission(loop_seqs,
+ uv_layer, uv_min,
+ width, height)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ # loop_seqs[horizontal][vertical][loop]
+ loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+ if not loop_seqs:
+ self.report({'WARNING'}, error)
+ return {'CANCELLED'}
+
+ # get height and width
+ uv_max, uv_min = self.__get_uv_max_min(loop_seqs, uv_layer)
+ width = uv_max.x - uv_min.x
+ height = uv_max.y - uv_min.y
+
+ self.__align(loop_seqs, uv_layer, uv_min, width, height)
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/align_uv_cursor.py b/uv_magic_uv/op/align_uv_cursor.py
index 6de4bbcf..ab4e93b4 100644
--- a/uv_magic_uv/op/align_uv_cursor.py
+++ b/uv_magic_uv/op/align_uv_cursor.py
@@ -26,11 +26,25 @@ __date__ = "17 Nov 2018"
import bpy
from mathutils import Vector
from bpy.props import EnumProperty, BoolProperty, FloatVectorProperty
+import bmesh
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import align_uv_cursor_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
@@ -40,17 +54,37 @@ class _Properties:
@classmethod
def init_props(cls, scene):
def auvc_get_cursor_loc(self):
- _, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
- 'IMAGE_EDITOR')
+ area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+ 'IMAGE_EDITOR')
+ if compat.check_version(2, 80, 0) < 0:
+ bd_size = common.get_uvimg_editor_board_size(area)
+ else:
+ bd_size = [1.0, 1.0]
loc = space.cursor_location
- self['muv_align_uv_cursor_cursor_loc'] = Vector((loc[0], loc[1]))
+
+ if bd_size[0] < 0.000001:
+ cx = 0.0
+ else:
+ cx = loc[0] / bd_size[0]
+ if bd_size[1] < 0.000001:
+ cy = 0.0
+ else:
+ cy = loc[1] / bd_size[1]
+
+ self['muv_align_uv_cursor_cursor_loc'] = Vector((cx, cy))
return self.get('muv_align_uv_cursor_cursor_loc', (0.0, 0.0))
def auvc_set_cursor_loc(self, value):
self['muv_align_uv_cursor_cursor_loc'] = value
- _, _, space = common.get_space_legacy('IMAGE_EDITOR', 'WINDOW',
- 'IMAGE_EDITOR')
- space.cursor_location = Vector((value[0], value[1]))
+ area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+ 'IMAGE_EDITOR')
+ if compat.check_version(2, 80, 0) < 0:
+ bd_size = common.get_uvimg_editor_board_size(area)
+ else:
+ bd_size = [1.0, 1.0]
+ cx = bd_size[0] * value[0]
+ cy = bd_size[1] * value[1]
+ space.cursor_location = Vector((cx, cy))
scene.muv_align_uv_cursor_enabled = BoolProperty(
name="Align UV Cursor Enabled",
@@ -96,6 +130,7 @@ class _Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_AlignUVCursor(bpy.types.Operator):
bl_idname = "uv.muv_align_uv_cursor_operator"
@@ -103,7 +138,7 @@ class MUV_OT_AlignUVCursor(bpy.types.Operator):
bl_description = "Align cursor to the center of UV island"
bl_options = {'REGISTER', 'UNDO'}
- position: EnumProperty(
+ position = EnumProperty(
items=(
('CENTER', "Center", "Align to Center"),
('LEFT_TOP', "Left Top", "Align to Left Top"),
@@ -119,7 +154,7 @@ class MUV_OT_AlignUVCursor(bpy.types.Operator):
description="Align position",
default='CENTER'
)
- base: EnumProperty(
+ base = EnumProperty(
items=(
('TEXTURE', "Texture", "Align based on Texture"),
('UV', "UV", "Align to UV"),
@@ -130,12 +165,105 @@ class MUV_OT_AlignUVCursor(bpy.types.Operator):
default='TEXTURE'
)
- def __init__(self):
- self.__impl = impl.AlignUVCursorImpl()
-
@classmethod
def poll(cls, context):
- return impl.AlignUVCursorImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ area, _, space = common.get_space('IMAGE_EDITOR', 'WINDOW',
+ 'IMAGE_EDITOR')
+ if compat.check_version(2, 80, 0) < 0:
+ bd_size = common.get_uvimg_editor_board_size(area)
+ else:
+ bd_size = [1.0, 1.0]
+
+ if self.base == 'UV':
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if not bm.loops.layers.uv:
+ return None
+ uv_layer = bm.loops.layers.uv.verify()
+
+ max_ = Vector((-10000000.0, -10000000.0))
+ min_ = Vector((10000000.0, 10000000.0))
+ for f in bm.faces:
+ if not f.select:
+ continue
+ for l in f.loops:
+ uv = l[uv_layer].uv
+ max_.x = max(max_.x, uv.x)
+ max_.y = max(max_.y, uv.y)
+ min_.x = min(min_.x, uv.x)
+ min_.y = min(min_.y, uv.y)
+ center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
+
+ elif self.base == 'UV_SEL':
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if not bm.loops.layers.uv:
+ return None
+ uv_layer = bm.loops.layers.uv.verify()
+
+ max_ = Vector((-10000000.0, -10000000.0))
+ min_ = Vector((10000000.0, 10000000.0))
+ for f in bm.faces:
+ if not f.select:
+ continue
+ for l in f.loops:
+ if not l[uv_layer].select:
+ continue
+ uv = l[uv_layer].uv
+ max_.x = max(max_.x, uv.x)
+ max_.y = max(max_.y, uv.y)
+ min_.x = min(min_.x, uv.x)
+ min_.y = min(min_.y, uv.y)
+ center = Vector(((max_.x + min_.x) / 2.0, (max_.y + min_.y) / 2.0))
+
+ elif self.base == 'TEXTURE':
+ min_ = Vector((0.0, 0.0))
+ max_ = Vector((1.0, 1.0))
+ center = Vector((0.5, 0.5))
+ else:
+ self.report({'ERROR'}, "Unknown Operation")
+ return {'CANCELLED'}
+
+ if self.position == 'CENTER':
+ cx = center.x
+ cy = center.y
+ elif self.position == 'LEFT_TOP':
+ cx = min_.x
+ cy = max_.y
+ elif self.position == 'LEFT_MIDDLE':
+ cx = min_.x
+ cy = center.y
+ elif self.position == 'LEFT_BOTTOM':
+ cx = min_.x
+ cy = min_.y
+ elif self.position == 'MIDDLE_TOP':
+ cx = center.x
+ cy = max_.y
+ elif self.position == 'MIDDLE_BOTTOM':
+ cx = center.x
+ cy = min_.y
+ elif self.position == 'RIGHT_TOP':
+ cx = max_.x
+ cy = max_.y
+ elif self.position == 'RIGHT_MIDDLE':
+ cx = max_.x
+ cy = center.y
+ elif self.position == 'RIGHT_BOTTOM':
+ cx = max_.x
+ cy = min_.y
+ else:
+ self.report({'ERROR'}, "Unknown Operation")
+ return {'CANCELLED'}
+
+ cx = cx * bd_size[0]
+ cy = cy * bd_size[1]
+
+ space.cursor_location = Vector((cx, cy))
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/copy_paste_uv.py b/uv_magic_uv/op/copy_paste_uv.py
index 23bc8343..f5ff883e 100644
--- a/uv_magic_uv/op/copy_paste_uv.py
+++ b/uv_magic_uv/op/copy_paste_uv.py
@@ -23,7 +23,6 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
-
import bmesh
import bpy.utils
from bpy.props import (
@@ -33,26 +32,244 @@ from bpy.props import (
EnumProperty,
)
-from ..impl import copy_paste_uv_impl as impl
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
- 'Properties',
- 'MUV_OT_CopyPasteUV_CopyUV',
- 'MUV_MT_CopyPasteUV_CopyUV',
- 'MUV_OT_CopyPasteUV_PasteUV',
- 'MUV_MT_CopyPasteUV_PasteUV',
- 'MUV_OT_CopyPasteUV_SelSeqCopyUV',
- 'MUV_MT_CopyPasteUV_SelSeqCopyUV',
- 'MUV_OT_CopyPasteUV_SelSeqPasteUV',
- 'MUV_MT_CopyPasteUV_SelSeqPasteUV',
-]
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def get_copy_uv_layers(ops_obj, bm, uv_map):
+ uv_layers = []
+ if uv_map == "__default":
+ if not bm.loops.layers.uv:
+ ops_obj.report(
+ {'WARNING'}, "Object must have more than one UV map")
+ return None
+ uv_layers.append(bm.loops.layers.uv.verify())
+ ops_obj.report({'INFO'}, "Copy UV coordinate")
+ elif uv_map == "__all":
+ for uv in bm.loops.layers.uv.keys():
+ uv_layers.append(bm.loops.layers.uv[uv])
+ ops_obj.report({'INFO'}, "Copy UV coordinate (UV map: ALL)")
+ else:
+ uv_layers.append(bm.loops.layers.uv[uv_map])
+ ops_obj.report(
+ {'INFO'}, "Copy UV coordinate (UV map:{})".format(uv_map))
+
+ return uv_layers
+
+
+def get_paste_uv_layers(ops_obj, obj, bm, src_info, uv_map):
+ uv_layers = []
+ if uv_map == "__default":
+ if not bm.loops.layers.uv:
+ ops_obj.report(
+ {'WARNING'}, "Object must have more than one UV map")
+ return None
+ uv_layers.append(bm.loops.layers.uv.verify())
+ ops_obj.report({'INFO'}, "Paste UV coordinate")
+ elif uv_map == "__new":
+ new_uv_map = common.create_new_uv_map(obj)
+ if not new_uv_map:
+ ops_obj.report({'WARNING'},
+ "Reached to the maximum number of UV map")
+ return None
+ uv_layers.append(bm.loops.layers.uv[new_uv_map.name])
+ ops_obj.report(
+ {'INFO'}, "Paste UV coordinate (UV map:{})".format(new_uv_map))
+ elif uv_map == "__all":
+ for src_layer in src_info.keys():
+ if src_layer not in bm.loops.layers.uv.keys():
+ new_uv_map = common.create_new_uv_map(obj, src_layer)
+ if not new_uv_map:
+ ops_obj.report({'WARNING'},
+ "Reached to the maximum number of UV map")
+ return None
+ uv_layers.append(bm.loops.layers.uv[src_layer])
+ ops_obj.report({'INFO'}, "Paste UV coordinate (UV map: ALL)")
+ else:
+ uv_layers.append(bm.loops.layers.uv[uv_map])
+ ops_obj.report(
+ {'INFO'}, "Paste UV coordinate (UV map:{})".format(uv_map))
+
+ return uv_layers
+
+
+def get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
+ src_info = {}
+ for layer in uv_layers:
+ face_info = []
+ for face in bm.faces:
+ if not only_select or face.select:
+ info = {
+ "index": face.index,
+ "uvs": [l[layer].uv.copy() for l in face.loops],
+ "pin_uvs": [l[layer].pin_uv for l in face.loops],
+ "seams": [l.edge.seam for l in face.loops],
+ }
+ face_info.append(info)
+ if not face_info:
+ ops_obj.report({'WARNING'}, "No faces are selected")
+ return None
+ src_info[layer.name] = face_info
+
+ return src_info
+
+
+def get_dest_face_info(ops_obj, bm, uv_layers, src_info, strategy,
+ only_select=False):
+ dest_info = {}
+ for layer in uv_layers:
+ face_info = []
+ for face in bm.faces:
+ if not only_select or face.select:
+ info = {
+ "index": face.index,
+ "uvs": [l[layer].uv.copy() for l in face.loops],
+ }
+ face_info.append(info)
+ if not face_info:
+ ops_obj.report({'WARNING'}, "No faces are selected")
+ return None
+ key = list(src_info.keys())[0]
+ src_face_count = len(src_info[key])
+ dest_face_count = len(face_info)
+ if strategy == 'N_N' and src_face_count != dest_face_count:
+ ops_obj.report(
+ {'WARNING'},
+ "Number of selected faces is different from copied" +
+ "(src:{}, dest:{})"
+ .format(src_face_count, dest_face_count))
+ return None
+ dest_info[layer.name] = face_info
+
+ return dest_info
+
+
+def _get_select_history_src_face_info(ops_obj, bm, uv_layers):
+ src_info = {}
+ for layer in uv_layers:
+ face_info = []
+ for hist in bm.select_history:
+ if isinstance(hist, bmesh.types.BMFace) and hist.select:
+ info = {
+ "index": hist.index,
+ "uvs": [l[layer].uv.copy() for l in hist.loops],
+ "pin_uvs": [l[layer].pin_uv for l in hist.loops],
+ "seams": [l.edge.seam for l in hist.loops],
+ }
+ face_info.append(info)
+ if not face_info:
+ ops_obj.report({'WARNING'}, "No faces are selected")
+ return None
+ src_info[layer.name] = face_info
+
+ return src_info
+
+
+def _get_select_history_dest_face_info(ops_obj, bm, uv_layers, src_info,
+ strategy):
+ dest_info = {}
+ for layer in uv_layers:
+ face_info = []
+ for hist in bm.select_history:
+ if isinstance(hist, bmesh.types.BMFace) and hist.select:
+ info = {
+ "index": hist.index,
+ "uvs": [l[layer].uv.copy() for l in hist.loops],
+ }
+ face_info.append(info)
+ if not face_info:
+ ops_obj.report({'WARNING'}, "No faces are selected")
+ return None
+ key = list(src_info.keys())[0]
+ src_face_count = len(src_info[key])
+ dest_face_count = len(face_info)
+ if strategy == 'N_N' and src_face_count != dest_face_count:
+ ops_obj.report(
+ {'WARNING'},
+ "Number of selected faces is different from copied" +
+ "(src:{}, dest:{})"
+ .format(src_face_count, dest_face_count))
+ return None
+ dest_info[layer.name] = face_info
+
+ return dest_info
+
+
+def paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
+ rotate, copy_seams):
+ for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
+ src_faces = src_info[slayer_name]
+ dest_faces = dest_info[dlayer.name]
+
+ for idx, dinfo in enumerate(dest_faces):
+ sinfo = None
+ if strategy == 'N_N':
+ sinfo = src_faces[idx]
+ elif strategy == 'N_M':
+ sinfo = src_faces[idx % len(src_faces)]
+
+ suv = sinfo["uvs"]
+ spuv = sinfo["pin_uvs"]
+ ss = sinfo["seams"]
+ if len(sinfo["uvs"]) != len(dinfo["uvs"]):
+ ops_obj.report({'WARNING'}, "Some faces are different size")
+ return -1
+
+ suvs_fr = [uv for uv in suv]
+ spuvs_fr = [pin_uv for pin_uv in spuv]
+ ss_fr = [s for s in ss]
+
+ # flip UVs
+ if flip is True:
+ suvs_fr.reverse()
+ spuvs_fr.reverse()
+ ss_fr.reverse()
+
+ # rotate UVs
+ for _ in range(rotate):
+ uv = suvs_fr.pop()
+ pin_uv = spuvs_fr.pop()
+ s = ss_fr.pop()
+ suvs_fr.insert(0, uv)
+ spuvs_fr.insert(0, pin_uv)
+ ss_fr.insert(0, s)
+
+ # paste UVs
+ for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
+ suvs_fr, spuvs_fr, ss_fr):
+ l[dlayer].uv = suv
+ l[dlayer].pin_uv = spuv
+ if copy_seams is True:
+ l.edge.seam = ss
+
+ return 0
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "copy_paste_uv"
@classmethod
@@ -103,6 +320,7 @@ class Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
"""
Operation class: Copy UV coordinate
@@ -113,14 +331,14 @@ class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
bl_description = "Copy UV coordinate"
bl_options = {'REGISTER', 'UNDO'}
- uv_map: StringProperty(default="__default", options={'HIDDEN'})
+ uv_map = StringProperty(default="__default", options={'HIDDEN'})
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
if common.is_console_mode():
return True
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
props = context.scene.muv_props.copy_paste_uv
@@ -128,12 +346,12 @@ class MUV_OT_CopyPasteUV_CopyUV(bpy.types.Operator):
bm = common.create_bmesh(obj)
# get UV layer
- uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+ uv_layers = get_copy_uv_layers(self, bm, self.uv_map)
if not uv_layers:
return {'CANCELLED'}
# get selected face
- src_info = impl.get_src_face_info(self, bm, uv_layers)
+ src_info = get_src_face_info(self, bm, uv_layers, True)
if src_info is None:
return {'CANCELLED'}
props.src_info = src_info
@@ -156,7 +374,7 @@ class MUV_MT_CopyPasteUV_CopyUV(bpy.types.Menu):
@classmethod
def poll(cls, context):
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def draw(self, context):
layout = self.layout
@@ -179,6 +397,7 @@ class MUV_MT_CopyPasteUV_CopyUV(bpy.types.Menu):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
"""
Operation class: Paste UV coordinate
@@ -189,8 +408,8 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
bl_description = "Paste UV coordinate"
bl_options = {'REGISTER', 'UNDO'}
- uv_map: StringProperty(default="__default", options={'HIDDEN'})
- strategy: EnumProperty(
+ uv_map = StringProperty(default="__default", options={'HIDDEN'})
+ strategy = EnumProperty(
name="Strategy",
description="Paste Strategy",
items=[
@@ -199,18 +418,18 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
],
default="N_M"
)
- flip_copied_uv: BoolProperty(
+ flip_copied_uv = BoolProperty(
name="Flip Copied UV",
description="Flip Copied UV...",
default=False
)
- rotate_copied_uv: IntProperty(
+ rotate_copied_uv = IntProperty(
default=0,
name="Rotate Copied UV",
min=0,
max=30
)
- copy_seams: BoolProperty(
+ copy_seams = BoolProperty(
name="Seams",
description="Copy Seams",
default=True
@@ -225,7 +444,7 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
props = sc.muv_props.copy_paste_uv
if not props.src_info:
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
props = context.scene.muv_props.copy_paste_uv
@@ -236,21 +455,21 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
bm = common.create_bmesh(obj)
# get UV layer
- uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
- self.uv_map)
+ uv_layers = get_paste_uv_layers(self, obj, bm, props.src_info,
+ self.uv_map)
if not uv_layers:
return {'CANCELLED'}
# get selected face
- dest_info = impl.get_dest_face_info(self, bm, uv_layers,
- props.src_info, self.strategy)
+ dest_info = get_dest_face_info(self, bm, uv_layers,
+ props.src_info, self.strategy, True)
if dest_info is None:
return {'CANCELLED'}
# paste
- ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
- self.strategy, self.flip_copied_uv,
- self.rotate_copied_uv, self.copy_seams)
+ ret = paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+ self.strategy, self.flip_copied_uv,
+ self.rotate_copied_uv, self.copy_seams)
if ret:
return {'CANCELLED'}
@@ -259,6 +478,10 @@ class MUV_OT_CopyPasteUV_PasteUV(bpy.types.Operator):
bmesh.update_edit_mesh(obj.data)
+ if compat.check_version(2, 80, 0) < 0:
+ if self.copy_seams is True:
+ obj.data.show_edge_seams = True
+
return {'FINISHED'}
@@ -278,7 +501,7 @@ class MUV_MT_CopyPasteUV_PasteUV(bpy.types.Menu):
props = sc.muv_props.copy_paste_uv
if not props.src_info:
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def draw(self, context):
sc = context.scene
@@ -314,6 +537,7 @@ class MUV_MT_CopyPasteUV_PasteUV(bpy.types.Menu):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
"""
Operation class: Copy UV coordinate by selection sequence
@@ -324,14 +548,14 @@ class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
bl_description = "Copy UV data by selection sequence"
bl_options = {'REGISTER', 'UNDO'}
- uv_map: StringProperty(default="__default", options={'HIDDEN'})
+ uv_map = StringProperty(default="__default", options={'HIDDEN'})
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
if common.is_console_mode():
return True
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
props = context.scene.muv_props.copy_paste_uv_selseq
@@ -339,12 +563,12 @@ class MUV_OT_CopyPasteUV_SelSeqCopyUV(bpy.types.Operator):
bm = common.create_bmesh(obj)
# get UV layer
- uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+ uv_layers = get_copy_uv_layers(self, bm, self.uv_map)
if not uv_layers:
return {'CANCELLED'}
# get selected face
- src_info = impl.get_select_history_src_face_info(self, bm, uv_layers)
+ src_info = _get_select_history_src_face_info(self, bm, uv_layers)
if src_info is None:
return {'CANCELLED'}
props.src_info = src_info
@@ -367,7 +591,7 @@ class MUV_MT_CopyPasteUV_SelSeqCopyUV(bpy.types.Menu):
@classmethod
def poll(cls, context):
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def draw(self, context):
layout = self.layout
@@ -390,6 +614,7 @@ class MUV_MT_CopyPasteUV_SelSeqCopyUV(bpy.types.Menu):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
"""
Operation class: Paste UV coordinate by selection sequence
@@ -400,8 +625,8 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
bl_description = "Paste UV coordinate by selection sequence"
bl_options = {'REGISTER', 'UNDO'}
- uv_map: StringProperty(default="__default", options={'HIDDEN'})
- strategy: EnumProperty(
+ uv_map = StringProperty(default="__default", options={'HIDDEN'})
+ strategy = EnumProperty(
name="Strategy",
description="Paste Strategy",
items=[
@@ -410,18 +635,18 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
],
default="N_M"
)
- flip_copied_uv: BoolProperty(
+ flip_copied_uv = BoolProperty(
name="Flip Copied UV",
description="Flip Copied UV...",
default=False
)
- rotate_copied_uv: IntProperty(
+ rotate_copied_uv = IntProperty(
default=0,
name="Rotate Copied UV",
min=0,
max=30
)
- copy_seams: BoolProperty(
+ copy_seams = BoolProperty(
name="Seams",
description="Copy Seams",
default=True
@@ -436,7 +661,7 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
props = sc.muv_props.copy_paste_uv_selseq
if not props.src_info:
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
props = context.scene.muv_props.copy_paste_uv_selseq
@@ -447,22 +672,22 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
bm = common.create_bmesh(obj)
# get UV layer
- uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
- self.uv_map)
+ uv_layers = get_paste_uv_layers(self, obj, bm, props.src_info,
+ self.uv_map)
if not uv_layers:
return {'CANCELLED'}
# get selected face
- dest_info = impl.get_select_history_dest_face_info(self, bm, uv_layers,
- props.src_info,
- self.strategy)
+ dest_info = _get_select_history_dest_face_info(self, bm, uv_layers,
+ props.src_info,
+ self.strategy)
if dest_info is None:
return {'CANCELLED'}
# paste
- ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
- self.strategy, self.flip_copied_uv,
- self.rotate_copied_uv, self.copy_seams)
+ ret = paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+ self.strategy, self.flip_copied_uv,
+ self.rotate_copied_uv, self.copy_seams)
if ret:
return {'CANCELLED'}
@@ -471,6 +696,10 @@ class MUV_OT_CopyPasteUV_SelSeqPasteUV(bpy.types.Operator):
bmesh.update_edit_mesh(obj.data)
+ if compat.check_version(2, 80, 0) < 0:
+ if self.copy_seams is True:
+ obj.data.show_edge_seams = True
+
return {'FINISHED'}
@@ -490,7 +719,7 @@ class MUV_MT_CopyPasteUV_SelSeqPasteUV(bpy.types.Menu):
props = sc.muv_props.copy_paste_uv_selseq
if not props.src_uvs or not props.src_pin_uvs:
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def draw(self, context):
sc = context.scene
diff --git a/uv_magic_uv/op/copy_paste_uv_object.py b/uv_magic_uv/op/copy_paste_uv_object.py
index d9f42447..dc7073b8 100644
--- a/uv_magic_uv/op/copy_paste_uv_object.py
+++ b/uv_magic_uv/op/copy_paste_uv_object.py
@@ -30,21 +30,20 @@ from bpy.props import (
BoolProperty,
)
-from ..impl import copy_paste_uv_impl as impl
+from .copy_paste_uv import (
+ get_copy_uv_layers,
+ get_src_face_info,
+ get_paste_uv_layers,
+ get_dest_face_info,
+ paste_uv,
+)
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-
-__all__ = [
- 'Properties',
- 'MUV_OT_CopyPasteUVObject_CopyUV',
- 'MUV_MT_CopyPasteUVObject_CopyUV',
- 'MUV_OT_CopyPasteUVObject_PasteUV',
- 'MUV_MT_CopyPasteUVObject_PasteUV',
-]
+from ..utils import compatibility as compat
-def is_valid_context(context):
+def _is_valid_context(context):
obj = context.object
# only object mode is allowed to execute
@@ -66,7 +65,7 @@ def is_valid_context(context):
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "copy_paste_uv_object"
@classmethod
@@ -98,6 +97,7 @@ def memorize_view_3d_mode(fn):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
"""
Operation class: Copy UV coordinate among objects
@@ -108,14 +108,14 @@ class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
bl_description = "Copy UV coordinate (Among Objects)"
bl_options = {'REGISTER', 'UNDO'}
- uv_map: StringProperty(default="__default", options={'HIDDEN'})
+ uv_map = StringProperty(default="__default", options={'HIDDEN'})
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
if common.is_console_mode():
return True
- return is_valid_context(context)
+ return _is_valid_context(context)
@memorize_view_3d_mode
def execute(self, context):
@@ -125,12 +125,12 @@ class MUV_OT_CopyPasteUVObject_CopyUV(bpy.types.Operator):
bm = common.create_bmesh(obj)
# get UV layer
- uv_layers = impl.get_copy_uv_layers(self, bm, self.uv_map)
+ uv_layers = get_copy_uv_layers(self, bm, self.uv_map)
if not uv_layers:
return {'CANCELLED'}
# get selected face
- src_info = impl.get_src_face_info(self, bm, uv_layers)
+ src_info = get_src_face_info(self, bm, uv_layers)
if src_info is None:
return {'CANCELLED'}
props.src_info = src_info
@@ -153,12 +153,12 @@ class MUV_MT_CopyPasteUVObject_CopyUV(bpy.types.Menu):
@classmethod
def poll(cls, context):
- return is_valid_context(context)
+ return _is_valid_context(context)
def draw(self, _):
layout = self.layout
# create sub menu
- uv_maps = bpy.context.active_object.data.uv_layers.keys()
+ uv_maps = compat.get_object_uv_layers(bpy.context.active_object).keys()
ops = layout.operator(MUV_OT_CopyPasteUVObject_CopyUV.bl_idname,
text="[Default]")
@@ -175,6 +175,7 @@ class MUV_MT_CopyPasteUVObject_CopyUV(bpy.types.Menu):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
"""
Operation class: Paste UV coordinate among objects
@@ -185,8 +186,8 @@ class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
bl_description = "Paste UV coordinate (Among Objects)"
bl_options = {'REGISTER', 'UNDO'}
- uv_map: StringProperty(default="__default", options={'HIDDEN'})
- copy_seams: BoolProperty(
+ uv_map = StringProperty(default="__default", options={'HIDDEN'})
+ copy_seams = BoolProperty(
name="Seams",
description="Copy Seams",
default=True
@@ -201,7 +202,7 @@ class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
props = sc.muv_props.copy_paste_uv_object
if not props.src_info:
return False
- return is_valid_context(context)
+ return _is_valid_context(context)
@memorize_view_3d_mode
def execute(self, context):
@@ -211,36 +212,40 @@ class MUV_OT_CopyPasteUVObject_PasteUV(bpy.types.Operator):
return {'CANCELLED'}
for o in bpy.data.objects:
- if not hasattr(o.data, "uv_layers") or not o.select_get():
+ if not compat.object_has_uv_layers(o) or not compat.get_object_select(o):
continue
bpy.ops.object.mode_set(mode='OBJECT')
- bpy.context.view_layer.objects.active = o
+ compat.set_active_object(o)
bpy.ops.object.mode_set(mode='EDIT')
obj = context.active_object
bm = common.create_bmesh(obj)
# get UV layer
- uv_layers = impl.get_paste_uv_layers(self, obj, bm, props.src_info,
- self.uv_map)
+ uv_layers = get_paste_uv_layers(self, obj, bm, props.src_info,
+ self.uv_map)
if not uv_layers:
return {'CANCELLED'}
# get selected face
- dest_info = impl.get_dest_face_info(self, bm, uv_layers,
- props.src_info, 'N_N')
+ dest_info = get_dest_face_info(self, bm, uv_layers,
+ props.src_info, 'N_N')
if dest_info is None:
return {'CANCELLED'}
# paste
- ret = impl.paste_uv(self, bm, props.src_info, dest_info, uv_layers,
- 'N_N', 0, 0, self.copy_seams)
+ ret = paste_uv(self, bm, props.src_info, dest_info, uv_layers,
+ 'N_N', 0, 0, self.copy_seams)
if ret:
return {'CANCELLED'}
bmesh.update_edit_mesh(obj.data)
+ if compat.check_version(2, 80, 0) < 0:
+ if self.copy_seams is True:
+ obj.data.show_edge_seams = True
+
self.report(
{'INFO'}, "{}'s UV coordinates are pasted".format(obj.name))
@@ -263,7 +268,7 @@ class MUV_MT_CopyPasteUVObject_PasteUV(bpy.types.Menu):
props = sc.muv_props.copy_paste_uv_object
if not props.src_info:
return False
- return is_valid_context(context)
+ return _is_valid_context(context)
def draw(self, context):
sc = context.scene
@@ -271,8 +276,8 @@ class MUV_MT_CopyPasteUVObject_PasteUV(bpy.types.Menu):
# create sub menu
uv_maps = []
for obj in bpy.data.objects:
- if hasattr(obj.data, "uv_layers") and obj.select_get():
- uv_maps.extend(obj.data.uv_layers.keys())
+ if compat.object_has_uv_layers(obj) and compat.get_object_select(obj):
+ uv_maps.extend(compat.get_object_uv_layers(obj).keys())
ops = layout.operator(MUV_OT_CopyPasteUVObject_PasteUV.bl_idname,
text="[Default]")
diff --git a/uv_magic_uv/op/copy_paste_uv_uvedit.py b/uv_magic_uv/op/copy_paste_uv_uvedit.py
index 719687a6..16c0dfa5 100644
--- a/uv_magic_uv/op/copy_paste_uv_uvedit.py
+++ b/uv_magic_uv/op/copy_paste_uv_uvedit.py
@@ -24,21 +24,43 @@ __version__ = "5.2"
__date__ = "17 Nov 2018"
import bpy
+import math
+from math import atan2, sin, cos
+
+import bmesh
+from mathutils import Vector
+
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import copy_paste_uv_uvedit_impl as impl
-__all__ = [
- 'Properties',
- 'MUV_OT_CopyPasteUVUVEdit_CopyUV',
- 'MUV_OT_CopyPasteUVUVEdit_PasteUV',
-]
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "copy_paste_uv_uvedit"
@classmethod
@@ -64,15 +86,35 @@ class MUV_OT_CopyPasteUVUVEdit_CopyUV(bpy.types.Operator):
bl_description = "Copy UV coordinate (only selected in UV/Image Editor)"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.CopyUVImpl()
-
@classmethod
def poll(cls, context):
- return impl.CopyUVImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ props = context.scene.muv_props.copy_paste_uv_uvedit
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ uv_layer = bm.loops.layers.uv.verify()
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+
+ props.src_uvs = []
+ for face in bm.faces:
+ if not face.select:
+ continue
+ skip = False
+ for l in face.loops:
+ if not l[uv_layer].select:
+ skip = True
+ break
+ if skip:
+ continue
+ props.src_uvs.append([l[uv_layer].uv.copy() for l in face.loops])
+
+ return {'FINISHED'}
@BlClassRegistry()
@@ -86,12 +128,72 @@ class MUV_OT_CopyPasteUVUVEdit_PasteUV(bpy.types.Operator):
bl_description = "Paste UV coordinate (only selected in UV/Image Editor)"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.PasteUVImpl()
-
@classmethod
def poll(cls, context):
- return impl.PasteUVImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ sc = context.scene
+ props = sc.muv_props.copy_paste_uv_uvedit
+ if not props.src_uvs:
+ return False
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ props = context.scene.muv_props.copy_paste_uv_uvedit
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ uv_layer = bm.loops.layers.uv.verify()
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+
+ dest_uvs = []
+ dest_face_indices = []
+ for face in bm.faces:
+ if not face.select:
+ continue
+ skip = False
+ for l in face.loops:
+ if not l[uv_layer].select:
+ skip = True
+ break
+ if skip:
+ continue
+ dest_face_indices.append(face.index)
+ uvs = [l[uv_layer].uv.copy() for l in face.loops]
+ dest_uvs.append(uvs)
+
+ for suvs, duvs in zip(props.src_uvs, dest_uvs):
+ src_diff = suvs[1] - suvs[0]
+ dest_diff = duvs[1] - duvs[0]
+
+ src_base = suvs[0]
+ dest_base = duvs[0]
+
+ src_rad = atan2(src_diff.y, src_diff.x)
+ dest_rad = atan2(dest_diff.y, dest_diff.x)
+ if src_rad < dest_rad:
+ radian = dest_rad - src_rad
+ elif src_rad > dest_rad:
+ radian = math.pi * 2 - (src_rad - dest_rad)
+ else: # src_rad == dest_rad
+ radian = 0.0
+
+ ratio = dest_diff.length / src_diff.length
+ break
+
+ for suvs, fidx in zip(props.src_uvs, dest_face_indices):
+ for l, suv in zip(bm.faces[fidx].loops, suvs):
+ base = suv - src_base
+ radian_ref = atan2(base.y, base.x)
+ radian_fin = (radian + radian_ref)
+ length = base.length
+ turn = Vector((length * cos(radian_fin),
+ length * sin(radian_fin)))
+ target_uv = Vector((turn.x * ratio, turn.y * ratio)) + \
+ dest_base
+ l[uv_layer].uv = target_uv
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/flip_rotate_uv.py b/uv_magic_uv/op/flip_rotate_uv.py
index d1637052..2ecab254 100644
--- a/uv_magic_uv/op/flip_rotate_uv.py
+++ b/uv_magic_uv/op/flip_rotate_uv.py
@@ -33,16 +33,113 @@ from bpy.props import (
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import flip_rotate_impl as impl
-
-__all__ = [
- 'Properties',
- 'MUV_OT_FlipRotate',
-]
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def _get_uv_layer(ops_obj, bm):
+ # get UV layer
+ if not bm.loops.layers.uv:
+ ops_obj.report({'WARNING'}, "Object must have more than one UV map")
+ return None
+ uv_layer = bm.loops.layers.uv.verify()
+
+ return uv_layer
+
+
+def _get_src_face_info(ops_obj, bm, uv_layers, only_select=False):
+ src_info = {}
+ for layer in uv_layers:
+ face_info = []
+ for face in bm.faces:
+ if not only_select or face.select:
+ info = {
+ "index": face.index,
+ "uvs": [l[layer].uv.copy() for l in face.loops],
+ "pin_uvs": [l[layer].pin_uv for l in face.loops],
+ "seams": [l.edge.seam for l in face.loops],
+ }
+ face_info.append(info)
+ if not face_info:
+ ops_obj.report({'WARNING'}, "No faces are selected")
+ return None
+ src_info[layer.name] = face_info
+
+ return src_info
+
+
+def _paste_uv(ops_obj, bm, src_info, dest_info, uv_layers, strategy, flip,
+ rotate, copy_seams):
+ for slayer_name, dlayer in zip(src_info.keys(), uv_layers):
+ src_faces = src_info[slayer_name]
+ dest_faces = dest_info[dlayer.name]
+
+ for idx, dinfo in enumerate(dest_faces):
+ sinfo = None
+ if strategy == 'N_N':
+ sinfo = src_faces[idx]
+ elif strategy == 'N_M':
+ sinfo = src_faces[idx % len(src_faces)]
+
+ suv = sinfo["uvs"]
+ spuv = sinfo["pin_uvs"]
+ ss = sinfo["seams"]
+ if len(sinfo["uvs"]) != len(dinfo["uvs"]):
+ ops_obj.report({'WARNING'}, "Some faces are different size")
+ return -1
+
+ suvs_fr = [uv for uv in suv]
+ spuvs_fr = [pin_uv for pin_uv in spuv]
+ ss_fr = [s for s in ss]
+
+ # flip UVs
+ if flip is True:
+ suvs_fr.reverse()
+ spuvs_fr.reverse()
+ ss_fr.reverse()
+
+ # rotate UVs
+ for _ in range(rotate):
+ uv = suvs_fr.pop()
+ pin_uv = spuvs_fr.pop()
+ s = ss_fr.pop()
+ suvs_fr.insert(0, uv)
+ spuvs_fr.insert(0, pin_uv)
+ ss_fr.insert(0, s)
+
+ # paste UVs
+ for l, suv, spuv, ss in zip(bm.faces[dinfo["index"]].loops,
+ suvs_fr, spuvs_fr, ss_fr):
+ l[dlayer].uv = suv
+ l[dlayer].pin_uv = spuv
+ if copy_seams is True:
+ l.edge.seam = ss
+
+ return 0
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "flip_rotate_uv"
@classmethod
@@ -65,6 +162,7 @@ class Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_FlipRotate(bpy.types.Operator):
"""
Operation class: Flip and Rotate UV coordinate
@@ -75,18 +173,18 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
bl_description = "Flip/Rotate UV coordinate"
bl_options = {'REGISTER', 'UNDO'}
- flip: BoolProperty(
+ flip = BoolProperty(
name="Flip UV",
description="Flip UV...",
default=False
)
- rotate: IntProperty(
+ rotate = IntProperty(
default=0,
name="Rotate UV",
min=0,
max=30
)
- seams: BoolProperty(
+ seams = BoolProperty(
name="Seams",
description="Seams",
default=True
@@ -97,7 +195,7 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return True
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
self.report({'INFO'}, "Flip/Rotate UV")
@@ -107,12 +205,12 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
bm.faces.ensure_lookup_table()
# get UV layer
- uv_layer = impl.get_uv_layer(self, bm)
+ uv_layer = _get_uv_layer(self, bm)
if not uv_layer:
return {'CANCELLED'}
# get selected face
- src_info = impl.get_src_face_info(self, bm, [uv_layer], True)
+ src_info = _get_src_face_info(self, bm, [uv_layer], True)
if not src_info:
return {'CANCELLED'}
@@ -120,11 +218,15 @@ class MUV_OT_FlipRotate(bpy.types.Operator):
self.report({'INFO'}, "{} face(s) are selected".format(face_count))
# paste
- ret = impl.paste_uv(self, bm, src_info, src_info, [uv_layer], 'N_N',
- self.flip, self.rotate, self.seams)
+ ret = _paste_uv(self, bm, src_info, src_info, [uv_layer], 'N_N',
+ self.flip, self.rotate, self.seams)
if ret:
return {'CANCELLED'}
bmesh.update_edit_mesh(obj.data)
+ if compat.check_version(2, 80, 0) < 0:
+ if self.seams is True:
+ obj.data.show_edge_seams = True
+
return {'FINISHED'}
diff --git a/uv_magic_uv/op/mirror_uv.py b/uv_magic_uv/op/mirror_uv.py
index 6793ca23..b806daea 100644
--- a/uv_magic_uv/op/mirror_uv.py
+++ b/uv_magic_uv/op/mirror_uv.py
@@ -29,20 +29,80 @@ from bpy.props import (
FloatProperty,
BoolProperty,
)
+import bmesh
+from mathutils import Vector
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import mirror_uv_impl as impl
+from ..utils import compatibility as compat
+from .. import common
-__all__ = [
- 'Properties',
- 'MUV_OT_MirrorUV',
-]
+def is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def is_vector_similar(v1, v2, error):
+ """
+ Check if two vectors are similar, within an error threshold
+ """
+ within_err_x = abs(v2.x - v1.x) < error
+ within_err_y = abs(v2.y - v1.y) < error
+ within_err_z = abs(v2.z - v1.z) < error
+
+ return within_err_x and within_err_y and within_err_z
+
+
+def mirror_uvs(uv_layer, src, dst, axis, error):
+ """
+ Copy UV coordinates from one UV face to another
+ """
+ for sl in src.loops:
+ suv = sl[uv_layer].uv.copy()
+ svco = sl.vert.co.copy()
+ for dl in dst.loops:
+ dvco = dl.vert.co.copy()
+ if axis == 'X':
+ dvco.x = -dvco.x
+ elif axis == 'Y':
+ dvco.y = -dvco.y
+ elif axis == 'Z':
+ dvco.z = -dvco.z
+
+ if is_vector_similar(svco, dvco, error):
+ dl[uv_layer].uv = suv.copy()
+
+
+def get_face_center(face):
+ """
+ Get center coordinate of the face
+ """
+ center = Vector((0.0, 0.0, 0.0))
+ for v in face.verts:
+ center = center + v.co
+
+ return center / len(face.verts)
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "mirror_uv"
@classmethod
@@ -70,6 +130,7 @@ class Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_MirrorUV(bpy.types.Operator):
"""
Operation class: Mirror UV
@@ -79,7 +140,7 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
bl_label = "Mirror UV"
bl_options = {'REGISTER', 'UNDO'}
- axis: EnumProperty(
+ axis = EnumProperty(
items=(
('X', "X", "Mirror Along X axis"),
('Y', "Y", "Mirror Along Y axis"),
@@ -89,7 +150,7 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
description="Mirror Axis",
default='X'
)
- error: FloatProperty(
+ error = FloatProperty(
name="Error",
description="Error threshold",
default=0.001,
@@ -99,12 +160,56 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
soft_max=1.0
)
- def __init__(self):
- self.__impl = impl.MirrorUVImpl()
-
@classmethod
def poll(cls, context):
- return impl.MirrorUVImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+
+ error = self.error
+ axis = self.axis
+
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ 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()
+
+ faces = [f for f in bm.faces if f.select]
+ for f_dst in faces:
+ count = len(f_dst.verts)
+ for f_src in bm.faces:
+ # check if this is a candidate to do mirror UV
+ if f_src.index == f_dst.index:
+ continue
+ if count != len(f_src.verts):
+ continue
+
+ # test if the vertices x values are the same sign
+ dst = get_face_center(f_dst)
+ src = get_face_center(f_src)
+ if (dst.x > 0 and src.x > 0) or (dst.x < 0 and src.x < 0):
+ continue
+
+ # invert source axis
+ if axis == 'X':
+ src.x = -src.x
+ elif axis == 'Y':
+ src.y = -src.z
+ elif axis == 'Z':
+ src.z = -src.z
+
+ # do mirror UV
+ if is_vector_similar(dst, src, error):
+ mirror_uvs(uv_layer, f_src, f_dst, self.axis, self.error)
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/move_uv.py b/uv_magic_uv/op/move_uv.py
index 653918d3..b747892a 100644
--- a/uv_magic_uv/op/move_uv.py
+++ b/uv_magic_uv/op/move_uv.py
@@ -25,20 +25,51 @@ __date__ = "17 Nov 2018"
import bpy
from bpy.props import BoolProperty
+import bmesh
+from mathutils import Vector
-from ..impl import move_uv_impl as impl
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-__all__ = [
- 'Properties',
- 'MUV_OT_MoveUV',
-]
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def _find_uv(context):
+ bm = bmesh.from_edit_mesh(context.object.data)
+ topology_dict = []
+ uvs = []
+ active_uv = bm.loops.layers.uv.active
+ for fidx, f in enumerate(bm.faces):
+ for vidx, v in enumerate(f.verts):
+ if v.select:
+ uvs.append(f.loops[vidx][active_uv].uv.copy())
+ topology_dict.append([fidx, vidx])
+
+ return topology_dict, uvs
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "move_uv"
@classmethod
@@ -64,19 +95,91 @@ class MUV_OT_MoveUV(bpy.types.Operator):
bl_label = "Move UV"
bl_options = {'REGISTER', 'UNDO'}
+ __running = False
+
def __init__(self):
- self.__impl = impl.MoveUVImpl()
+ self.__topology_dict = []
+ self.__prev_mouse = Vector((0.0, 0.0))
+ self.__offset_uv = Vector((0.0, 0.0))
+ self.__prev_offset_uv = Vector((0.0, 0.0))
+ self.__first_time = True
+ self.__ini_uvs = []
+ self.__operating = False
@classmethod
def poll(cls, context):
- return impl.MoveUVImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return False
+ if cls.is_running(context):
+ return False
+ return _is_valid_context(context)
@classmethod
def is_running(cls, _):
- return impl.MoveUVImpl.is_running(_)
+ return cls.__running
def modal(self, context, event):
- return self.__impl.modal(self, context, event)
+ if self.__first_time is True:
+ self.__prev_mouse = Vector((
+ event.mouse_region_x, event.mouse_region_y))
+ self.__first_time = False
+ return {'RUNNING_MODAL'}
+
+ # move UV
+ div = 10000
+ self.__offset_uv += Vector((
+ (event.mouse_region_x - self.__prev_mouse.x) / div,
+ (event.mouse_region_y - self.__prev_mouse.y) / div))
+ ouv = self.__offset_uv
+ pouv = self.__prev_offset_uv
+ vec = Vector((ouv.x - ouv.y, ouv.x + ouv.y))
+ dv = vec - pouv
+ self.__prev_offset_uv = vec
+ self.__prev_mouse = Vector((
+ event.mouse_region_x, event.mouse_region_y))
+
+ # check if operation is started
+ if not self.__operating:
+ if event.type == 'LEFTMOUSE' and event.value == 'RELEASE':
+ self.__operating = True
+ return {'RUNNING_MODAL'}
+
+ # update UV
+ obj = context.object
+ bm = bmesh.from_edit_mesh(obj.data)
+ active_uv = bm.loops.layers.uv.active
+ for fidx, vidx in self.__topology_dict:
+ l = bm.faces[fidx].loops[vidx]
+ l[active_uv].uv = l[active_uv].uv + dv
+ bmesh.update_edit_mesh(obj.data)
+
+ # check mouse preference
+ confirm_btn = 'LEFTMOUSE'
+ cancel_btn = 'RIGHTMOUSE'
+
+ # cancelled
+ if event.type == cancel_btn and event.value == 'PRESS':
+ for (fidx, vidx), uv in zip(self.__topology_dict, self.__ini_uvs):
+ bm.faces[fidx].loops[vidx][active_uv].uv = uv
+ MUV_OT_MoveUV.__running = False
+ return {'FINISHED'}
+ # confirmed
+ if event.type == confirm_btn and event.value == 'PRESS':
+ MUV_OT_MoveUV.__running = False
+ return {'FINISHED'}
+
+ return {'RUNNING_MODAL'}
def execute(self, context):
- return self.__impl.execute(self, context)
+ MUV_OT_MoveUV.__running = True
+ self.__operating = False
+ self.__first_time = True
+
+ context.window_manager.modal_handler_add(self)
+ self.__topology_dict, self.__ini_uvs = _find_uv(context)
+
+ if context.area:
+ context.area.tag_redraw()
+
+ return {'RUNNING_MODAL'}
diff --git a/uv_magic_uv/op/pack_uv.py b/uv_magic_uv/op/pack_uv.py
index 84f195c5..35685221 100644
--- a/uv_magic_uv/op/pack_uv.py
+++ b/uv_magic_uv/op/pack_uv.py
@@ -23,26 +23,126 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
+from math import fabs
+
import bpy
from bpy.props import (
FloatProperty,
FloatVectorProperty,
BoolProperty,
)
+import bmesh
+import mathutils
+from mathutils import Vector
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import pack_uv_impl as impl
+from ..utils import compatibility as compat
+from .. import common
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
+
+
+def _sort_island_faces(kd, uvs, isl1, isl2):
+ """
+ Sort faces in island
+ """
+
+ sorted_faces = []
+ for f in isl1['sorted']:
+ _, idx, _ = kd.find(
+ Vector((f['ave_uv'].x, f['ave_uv'].y, 0.0)))
+ sorted_faces.append(isl2['faces'][uvs[idx]['face_idx']])
+ return sorted_faces
+
+def _group_island(island_info, allowable_center_deviation,
+ allowable_size_deviation):
+ """
+ Group island
+ """
+
+ num_group = 0
+ while True:
+ # search islands which is not parsed yet
+ isl_1 = None
+ for isl_1 in island_info:
+ if isl_1['group'] == -1:
+ break
+ else:
+ break # all faces are parsed
+ if isl_1 is None:
+ break
+ isl_1['group'] = num_group
+ isl_1['sorted'] = isl_1['faces']
-__all__ = [
- 'Properties',
- 'MUV_OT_PackUV',
-]
+ # search same island
+ for isl_2 in island_info:
+ if isl_2['group'] == -1:
+ dcx = isl_2['center'].x - isl_1['center'].x
+ dcy = isl_2['center'].y - isl_1['center'].y
+ dsx = isl_2['size'].x - isl_1['size'].x
+ dsy = isl_2['size'].y - isl_1['size'].y
+ center_x_matched = (
+ fabs(dcx) < allowable_center_deviation[0]
+ )
+ center_y_matched = (
+ fabs(dcy) < allowable_center_deviation[1]
+ )
+ size_x_matched = (
+ fabs(dsx) < allowable_size_deviation[0]
+ )
+ size_y_matched = (
+ fabs(dsy) < allowable_size_deviation[1]
+ )
+ center_matched = center_x_matched and center_y_matched
+ size_matched = size_x_matched and size_y_matched
+ num_uv_matched = (isl_2['num_uv'] == isl_1['num_uv'])
+ # are islands have same?
+ if center_matched and size_matched and num_uv_matched:
+ isl_2['group'] = num_group
+ kd = mathutils.kdtree.KDTree(len(isl_2['faces']))
+ uvs = [
+ {
+ 'uv': Vector(
+ (f['ave_uv'].x, f['ave_uv'].y, 0.0)
+ ),
+ 'face_idx': fidx
+ } for fidx, f in enumerate(isl_2['faces'])
+ ]
+ for i, uv in enumerate(uvs):
+ kd.insert(uv['uv'], i)
+ kd.balance()
+ # sort faces for copy/paste UV
+ isl_2['sorted'] = _sort_island_faces(kd, uvs, isl_1, isl_2)
+ num_group = num_group + 1
+
+ return num_group
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "pack_uv"
@classmethod
@@ -77,6 +177,7 @@ class Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_PackUV(bpy.types.Operator):
"""
Operation class: Pack UV with same UV islands are integrated
@@ -91,17 +192,17 @@ class MUV_OT_PackUV(bpy.types.Operator):
bl_description = "Pack UV (Same UV Islands are integrated)"
bl_options = {'REGISTER', 'UNDO'}
- rotate: BoolProperty(
+ rotate = BoolProperty(
name="Rotate",
description="Rotate option used by default pack UV function",
default=False)
- margin: FloatProperty(
+ margin = FloatProperty(
name="Margin",
description="Margin used by default pack UV function",
min=0,
max=1,
default=0.001)
- allowable_center_deviation: FloatVectorProperty(
+ allowable_center_deviation = FloatVectorProperty(
name="Allowable Center Deviation",
description="Allowable center deviation to judge same UV island",
min=0.000001,
@@ -109,7 +210,7 @@ class MUV_OT_PackUV(bpy.types.Operator):
default=(0.001, 0.001),
size=2
)
- allowable_size_deviation: FloatVectorProperty(
+ allowable_size_deviation = FloatVectorProperty(
name="Allowable Size Deviation",
description="Allowable sizse deviation to judge same UV island",
min=0.000001,
@@ -118,12 +219,64 @@ class MUV_OT_PackUV(bpy.types.Operator):
size=2
)
- def __init__(self):
- self.__impl = impl.PackUVImpl()
-
@classmethod
def poll(cls, context):
- return impl.PackUVImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ 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()
+
+ selected_faces = [f for f in bm.faces if f.select]
+ island_info = common.get_island_info(obj)
+ num_group = _group_island(island_info,
+ self.allowable_center_deviation,
+ self.allowable_size_deviation)
+
+ loop_lists = [l for f in bm.faces for l in f.loops]
+ bpy.ops.mesh.select_all(action='DESELECT')
+
+ # pack UV
+ for gidx in range(num_group):
+ group = list(filter(
+ lambda i, idx=gidx: i['group'] == idx, island_info))
+ for f in group[0]['faces']:
+ f['face'].select = True
+ bmesh.update_edit_mesh(obj.data)
+ bpy.ops.uv.select_all(action='SELECT')
+ bpy.ops.uv.pack_islands(rotate=self.rotate, margin=self.margin)
+
+ # copy/paste UV among same islands
+ for gidx in range(num_group):
+ group = list(filter(
+ lambda i, idx=gidx: i['group'] == idx, island_info))
+ if len(group) <= 1:
+ continue
+ for g in group[1:]:
+ for (src_face, dest_face) in zip(
+ group[0]['sorted'], g['sorted']):
+ for (src_loop, dest_loop) in zip(
+ src_face['face'].loops, dest_face['face'].loops):
+ loop_lists[dest_loop.index][uv_layer].uv = loop_lists[
+ src_loop.index][uv_layer].uv
+
+ # restore face/UV selection
+ bpy.ops.uv.select_all(action='DESELECT')
+ bpy.ops.mesh.select_all(action='DESELECT')
+ for f in selected_faces:
+ f.select = True
+ bpy.ops.uv.select_all(action='SELECT')
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/preserve_uv_aspect.py b/uv_magic_uv/op/preserve_uv_aspect.py
index ca4969fd..a200edac 100644
--- a/uv_magic_uv/op/preserve_uv_aspect.py
+++ b/uv_magic_uv/op/preserve_uv_aspect.py
@@ -25,16 +25,34 @@ __date__ = "17 Nov 2018"
import bpy
from bpy.props import StringProperty, EnumProperty, BoolProperty
+import bmesh
+from mathutils import Vector
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import preserve_uv_aspect_impl as impl
+from ..utils import compatibility as compat
-__all__ = [
- 'Properties',
- 'MUV_OT_PreserveUVAspect',
-]
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
@@ -84,6 +102,7 @@ class _Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_PreserveUVAspect(bpy.types.Operator):
"""
Operation class: Preserve UV Aspect
@@ -94,8 +113,8 @@ class MUV_OT_PreserveUVAspect(bpy.types.Operator):
bl_description = "Choose Image"
bl_options = {'REGISTER', 'UNDO'}
- dest_img_name: StringProperty(options={'HIDDEN'})
- origin: EnumProperty(
+ dest_img_name = StringProperty(options={'HIDDEN'})
+ origin = EnumProperty(
name="Origin",
description="Aspect Origin",
items=[
@@ -113,12 +132,166 @@ class MUV_OT_PreserveUVAspect(bpy.types.Operator):
default="CENTER"
)
- def __init__(self):
- self.__impl = impl.PreserveUVAspectImpl()
-
@classmethod
def poll(cls, context):
- return impl.PreserveUVAspectImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ # Note: the current system only works if the
+ # f[tex_layer].image doesn't return None
+ # which will happen in certain cases
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+
+ 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()
+
+ sel_faces = [f for f in bm.faces if f.select]
+ dest_img = bpy.data.images[self.dest_img_name]
+
+ info = {}
+
+ if compat.check_version(2, 80, 0) >= 0:
+ tex_image = common.find_image(obj)
+ for f in sel_faces:
+ if tex_image not in info.keys():
+ info[tex_image] = {}
+ info[tex_image]['faces'] = []
+ info[tex_image]['faces'].append(f)
+ else:
+ tex_layer = bm.faces.layers.tex.verify()
+ for f in sel_faces:
+ if not f[tex_layer].image in info.keys():
+ info[f[tex_layer].image] = {}
+ info[f[tex_layer].image]['faces'] = []
+ info[f[tex_layer].image]['faces'].append(f)
+
+ for img in info:
+ if img is None:
+ continue
+
+ src_img = img
+ ratio = Vector((
+ dest_img.size[0] / src_img.size[0],
+ dest_img.size[1] / src_img.size[1]))
+
+ 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)
+ else:
+ self.report({'ERROR'}, "Unknown Operation")
+ return {'CANCELLED'}
+
+ info[img]['ratio'] = ratio
+ info[img]['origin'] = origin
+
+ for img in info:
+ if img is None:
+ continue
+
+ if compat.check_version(2, 80, 0) >= 0:
+ nodes = common.find_texture_nodes(obj)
+ nodes[0].image = dest_img
+
+ for f in info[img]['faces']:
+ if compat.check_version(2, 80, 0) < 0:
+ tex_layer = bm.faces.layers.tex.verify()
+ f[tex_layer].image = dest_img
+ for l in f.loops:
+ uv = l[uv_layer].uv
+ 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)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/select_uv.py b/uv_magic_uv/op/select_uv.py
index 789af9ce..4664551e 100644
--- a/uv_magic_uv/op/select_uv.py
+++ b/uv_magic_uv/op/select_uv.py
@@ -25,10 +25,34 @@ __date__ = "17 Nov 2018"
import bpy
from bpy.props import BoolProperty
+import bmesh
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import select_uv_impl as impl
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
@@ -59,15 +83,38 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
bl_description = "Select faces which have overlapped UVs"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.SelectOverlappedImpl()
-
@classmethod
def poll(cls, context):
- return impl.SelectOverlappedImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ if context.tool_settings.use_uv_select_sync:
+ sel_faces = [f for f in bm.faces]
+ else:
+ sel_faces = [f for f in bm.faces if f.select]
+
+ overlapped_info = common.get_overlapped_uv_info(bm, sel_faces,
+ uv_layer, 'FACE')
+
+ for info in overlapped_info:
+ if context.tool_settings.use_uv_select_sync:
+ info["subject_face"].select = True
+ else:
+ for l in info["subject_face"].loops:
+ l[uv_layer].select = True
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
@BlClassRegistry()
@@ -81,12 +128,34 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
bl_description = "Select faces which have flipped UVs"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.SelectFlippedImpl()
-
@classmethod
def poll(cls, context):
- return impl.SelectFlippedImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ if context.tool_settings.use_uv_select_sync:
+ sel_faces = [f for f in bm.faces]
+ else:
+ sel_faces = [f for f in bm.faces if f.select]
+
+ flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
+
+ for info in flipped_info:
+ if context.tool_settings.use_uv_select_sync:
+ info["face"].select = True
+ else:
+ for l in info["face"].loops:
+ l[uv_layer].select = True
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/smooth_uv.py b/uv_magic_uv/op/smooth_uv.py
index d448d108..83a4a1a5 100644
--- a/uv_magic_uv/op/smooth_uv.py
+++ b/uv_magic_uv/op/smooth_uv.py
@@ -25,10 +25,35 @@ __date__ = "17 Nov 2018"
import bpy
from bpy.props import BoolProperty, FloatProperty
+import bmesh
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import smooth_uv_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
@@ -69,6 +94,7 @@ class _Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_SmoothUV(bpy.types.Operator):
bl_idname = "uv.muv_smooth_uv_operator"
@@ -76,30 +102,182 @@ class MUV_OT_SmoothUV(bpy.types.Operator):
bl_description = "Smooth UV coordinates"
bl_options = {'REGISTER', 'UNDO'}
- transmission: BoolProperty(
+ transmission = BoolProperty(
name="Transmission",
description="Smooth linked UVs",
default=False
)
- mesh_infl: FloatProperty(
+ mesh_infl = FloatProperty(
name="Mesh Influence",
description="Influence rate of mesh vertex",
min=0.0,
max=1.0,
default=0.0
)
- select: BoolProperty(
+ select = BoolProperty(
name="Select",
description="Select UVs which are smoothed",
default=False
)
- def __init__(self):
- self.__impl = impl.SmoothUVImpl()
-
@classmethod
def poll(cls, context):
- return impl.SmoothUVImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
+
+ def __smooth_wo_transmission(self, loop_seqs, uv_layer):
+ # calculate path length
+ loops = []
+ for hseq in loop_seqs:
+ loops.extend([hseq[0][0], hseq[0][1]])
+ full_vlen = 0
+ accm_vlens = [0.0]
+ full_uvlen = 0
+ accm_uvlens = [0.0]
+ orig_uvs = [loop_seqs[0][0][0][uv_layer].uv.copy()]
+ for l1, l2 in zip(loops[:-1], loops[1:]):
+ diff_v = l2.vert.co - l1.vert.co
+ full_vlen = full_vlen + diff_v.length
+ accm_vlens.append(full_vlen)
+ diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
+ full_uvlen = full_uvlen + diff_uv.length
+ accm_uvlens.append(full_uvlen)
+ orig_uvs.append(l2[uv_layer].uv.copy())
+
+ for hidx, hseq in enumerate(loop_seqs):
+ pair = hseq[0]
+ for pidx, l in enumerate(pair):
+ if self.select:
+ l[uv_layer].select = True
+
+ # ignore start/end loop
+ if (hidx == 0 and pidx == 0) or\
+ ((hidx == len(loop_seqs) - 1) and (pidx == len(pair) - 1)):
+ continue
+
+ # calculate target path length
+ # target = no influenced * (1 - infl) + influenced * infl
+ tgt_noinfl = full_uvlen * (hidx + pidx) / (len(loop_seqs))
+ tgt_infl = full_uvlen * accm_vlens[hidx * 2 + pidx] / full_vlen
+ target_length = tgt_noinfl * (1 - self.mesh_infl) + \
+ tgt_infl * self.mesh_infl
+
+ # get target UV
+ for i in range(len(accm_uvlens[:-1])):
+ # get line segment which UV will be placed
+ if ((accm_uvlens[i] <= target_length) and
+ (accm_uvlens[i + 1] > target_length)):
+ tgt_seg_len = target_length - accm_uvlens[i]
+ seg_len = accm_uvlens[i + 1] - accm_uvlens[i]
+ uv1 = orig_uvs[i]
+ uv2 = orig_uvs[i + 1]
+ target_uv = uv1 + (uv2 - uv1) * tgt_seg_len / seg_len
+ break
+ else:
+ self.report({'ERROR'}, "Failed to get target UV")
+ return {'CANCELLED'}
+
+ # update UV
+ l[uv_layer].uv = target_uv
+
+ def __smooth_w_transmission(self, loop_seqs, uv_layer):
+ # calculate path length
+ loops = []
+ for vidx in range(len(loop_seqs[0])):
+ ls = []
+ for hseq in loop_seqs:
+ ls.extend(hseq[vidx])
+ loops.append(ls)
+
+ orig_uvs = []
+ accm_vlens = []
+ full_vlens = []
+ accm_uvlens = []
+ full_uvlens = []
+ for ls in loops:
+ full_v = 0.0
+ accm_v = [0.0]
+ full_uv = 0.0
+ accm_uv = [0.0]
+ uvs = [ls[0][uv_layer].uv.copy()]
+ for l1, l2 in zip(ls[:-1], ls[1:]):
+ diff_v = l2.vert.co - l1.vert.co
+ full_v = full_v + diff_v.length
+ accm_v.append(full_v)
+ diff_uv = l2[uv_layer].uv - l1[uv_layer].uv
+ full_uv = full_uv + diff_uv.length
+ accm_uv.append(full_uv)
+ uvs.append(l2[uv_layer].uv.copy())
+ accm_vlens.append(accm_v)
+ full_vlens.append(full_v)
+ accm_uvlens.append(accm_uv)
+ full_uvlens.append(full_uv)
+ orig_uvs.append(uvs)
+
+ for hidx, hseq in enumerate(loop_seqs):
+ for vidx, (pair, uvs, accm_v, full_v, accm_uv, full_uv)\
+ in enumerate(zip(hseq, orig_uvs, accm_vlens, full_vlens,
+ accm_uvlens, full_uvlens)):
+ for pidx, l in enumerate(pair):
+ if self.select:
+ l[uv_layer].select = True
+
+ # ignore start/end loop
+ if hidx == 0 and pidx == 0:
+ continue
+ if hidx == len(loop_seqs) - 1 and pidx == len(pair) - 1:
+ continue
+
+ # calculate target path length
+ # target = no influenced * (1 - infl) + influenced * infl
+ tgt_noinfl = full_uv * (hidx + pidx) / (len(loop_seqs))
+ tgt_infl = full_uv * accm_v[hidx * 2 + pidx] / full_v
+ target_length = tgt_noinfl * (1 - self.mesh_infl) + \
+ tgt_infl * self.mesh_infl
+
+ # get target UV
+ for i in range(len(accm_uv[:-1])):
+ # get line segment to be placed
+ if ((accm_uv[i] <= target_length) and
+ (accm_uv[i + 1] > target_length)):
+ tgt_seg_len = target_length - accm_uv[i]
+ seg_len = accm_uv[i + 1] - accm_uv[i]
+ uv1 = uvs[i]
+ uv2 = uvs[i + 1]
+ target_uv = uv1 +\
+ (uv2 - uv1) * tgt_seg_len / seg_len
+ break
+ else:
+ self.report({'ERROR'}, "Failed to get target UV")
+ return {'CANCELLED'}
+
+ # update UV
+ l[uv_layer].uv = target_uv
+
+ def __smooth(self, loop_seqs, uv_layer):
+ if self.transmission:
+ self.__smooth_w_transmission(loop_seqs, uv_layer)
+ else:
+ self.__smooth_wo_transmission(loop_seqs, uv_layer)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ # loop_seqs[horizontal][vertical][loop]
+ loop_seqs, error = common.get_loop_sequences(bm, uv_layer)
+ if not loop_seqs:
+ self.report({'WARNING'}, error)
+ return {'CANCELLED'}
+
+ # smooth
+ self.__smooth(loop_seqs, uv_layer)
+
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/texture_lock.py b/uv_magic_uv/op/texture_lock.py
index b1b43753..f43a6fa9 100644
--- a/uv_magic_uv/op/texture_lock.py
+++ b/uv_magic_uv/op/texture_lock.py
@@ -23,12 +23,189 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
+import math
+from math import atan2, cos, sqrt, sin, fabs
+
import bpy
from bpy.props import BoolProperty
+import bmesh
+from mathutils import Vector
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import texture_lock_impl as impl
+from ..utils import compatibility as compat
+
+
+def _get_vco(verts_orig, loop):
+ """
+ Get vertex original coordinate from loop
+ """
+ for vo in verts_orig:
+ if vo["vidx"] == loop.vert.index and vo["moved"] is False:
+ return vo["vco"]
+ return loop.vert.co
+
+
+def _get_link_loops(vert):
+ """
+ Get loop linked to vertex
+ """
+ link_loops = []
+ for f in vert.link_faces:
+ adj_loops = []
+ for loop in f.loops:
+ # self loop
+ if loop.vert == vert:
+ l = loop
+ # linked loop
+ else:
+ for e in loop.vert.link_edges:
+ if e.other_vert(loop.vert) == vert:
+ adj_loops.append(loop)
+ if len(adj_loops) < 2:
+ return None
+
+ link_loops.append({"l": l, "l0": adj_loops[0], "l1": adj_loops[1]})
+ return link_loops
+
+
+def _get_ini_geom(link_loop, uv_layer, verts_orig, v_orig):
+ """
+ Get initial geometory
+ (Get interior angle of face in vertex/UV space)
+ """
+ u = link_loop["l"][uv_layer].uv
+ v0 = _get_vco(verts_orig, link_loop["l0"])
+ u0 = link_loop["l0"][uv_layer].uv
+ v1 = _get_vco(verts_orig, link_loop["l1"])
+ u1 = link_loop["l1"][uv_layer].uv
+
+ # get interior angle of face in vertex space
+ v0v1 = v1 - v0
+ v0v = v_orig["vco"] - v0
+ v1v = v_orig["vco"] - v1
+ theta0 = v0v1.angle(v0v)
+ theta1 = v0v1.angle(-v1v)
+ if (theta0 + theta1) > math.pi:
+ theta0 = v0v1.angle(-v0v)
+ theta1 = v0v1.angle(v1v)
+
+ # get interior angle of face in UV space
+ u0u1 = u1 - u0
+ u0u = u - u0
+ u1u = u - u1
+ phi0 = u0u1.angle(u0u)
+ phi1 = u0u1.angle(-u1u)
+ if (phi0 + phi1) > math.pi:
+ phi0 = u0u1.angle(-u0u)
+ phi1 = u0u1.angle(u1u)
+
+ # get direction of linked UV coordinate
+ # this will be used to judge whether angle is more or less than 180 degree
+ dir0 = u0u1.cross(u0u) > 0
+ dir1 = u0u1.cross(u1u) > 0
+
+ return {
+ "theta0": theta0,
+ "theta1": theta1,
+ "phi0": phi0,
+ "phi1": phi1,
+ "dir0": dir0,
+ "dir1": dir1}
+
+
+def _get_target_uv(link_loop, uv_layer, verts_orig, v, ini_geom):
+ """
+ Get target UV coordinate
+ """
+ v0 = _get_vco(verts_orig, link_loop["l0"])
+ lo0 = link_loop["l0"]
+ v1 = _get_vco(verts_orig, link_loop["l1"])
+ lo1 = link_loop["l1"]
+
+ # get interior angle of face in vertex space
+ v0v1 = v1 - v0
+ v0v = v.co - v0
+ v1v = v.co - v1
+ theta0 = v0v1.angle(v0v)
+ theta1 = v0v1.angle(-v1v)
+ if (theta0 + theta1) > math.pi:
+ theta0 = v0v1.angle(-v0v)
+ theta1 = v0v1.angle(v1v)
+
+ # calculate target interior angle in UV space
+ phi0 = theta0 * ini_geom["phi0"] / ini_geom["theta0"]
+ phi1 = theta1 * ini_geom["phi1"] / ini_geom["theta1"]
+
+ uv0 = lo0[uv_layer].uv
+ uv1 = lo1[uv_layer].uv
+
+ # calculate target vertex coordinate from target interior angle
+ tuv0, tuv1 = _calc_tri_vert(uv0, uv1, phi0, phi1)
+
+ # target UV coordinate depends on direction, so judge using direction of
+ # linked UV coordinate
+ u0u1 = uv1 - uv0
+ u0u = tuv0 - uv0
+ u1u = tuv0 - uv1
+ dir0 = u0u1.cross(u0u) > 0
+ dir1 = u0u1.cross(u1u) > 0
+ if (ini_geom["dir0"] != dir0) or (ini_geom["dir1"] != dir1):
+ return tuv1
+
+ return tuv0
+
+
+def _calc_tri_vert(v0, v1, angle0, angle1):
+ """
+ Calculate rest coordinate from other coordinates and angle of end
+ """
+ angle = math.pi - angle0 - angle1
+
+ alpha = atan2(v1.y - v0.y, v1.x - v0.x)
+ d = (v1.x - v0.x) / cos(alpha)
+ a = d * sin(angle0) / sin(angle)
+ b = d * sin(angle1) / sin(angle)
+ s = (a + b + d) / 2.0
+ if fabs(d) < 0.0000001:
+ xd = 0
+ yd = 0
+ else:
+ r = s * (s - a) * (s - b) * (s - d)
+ if r < 0:
+ xd = 0
+ yd = 0
+ else:
+ xd = (b * b - a * a + d * d) / (2 * d)
+ yd = 2 * sqrt(r) / d
+ x1 = xd * cos(alpha) - yd * sin(alpha) + v0.x
+ y1 = xd * sin(alpha) + yd * cos(alpha) + v0.y
+ x2 = xd * cos(alpha) + yd * sin(alpha) + v0.x
+ y2 = xd * sin(alpha) - yd * cos(alpha) + v0.y
+
+ return Vector((x1, y1)), Vector((x2, y2))
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
@@ -88,22 +265,43 @@ class MUV_OT_TextureLock_Lock(bpy.types.Operator):
bl_description = "Lock Texture"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.LockImpl()
-
@classmethod
def poll(cls, context):
- return impl.LockImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
@classmethod
def is_ready(cls, context):
- return impl.LockImpl.is_ready(context)
+ sc = context.scene
+ props = sc.muv_props.texture_lock
+ if props.verts_orig:
+ return True
+ return False
def execute(self, context):
- return self.__impl.execute(self, context)
+ props = context.scene.muv_props.texture_lock
+ obj = bpy.context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ if not bm.loops.layers.uv:
+ self.report({'WARNING'}, "Object must have more than one UV map")
+ return {'CANCELLED'}
+
+ props.verts_orig = [
+ {"vidx": v.index, "vco": v.co.copy(), "moved": False}
+ for v in bm.verts if v.select]
+
+ return {'FINISHED'}
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_TextureLock_Unlock(bpy.types.Operator):
"""
Operation class: Unlock Texture
@@ -114,20 +312,78 @@ class MUV_OT_TextureLock_Unlock(bpy.types.Operator):
bl_description = "Unlock Texture"
bl_options = {'REGISTER', 'UNDO'}
- connect: BoolProperty(
+ connect = BoolProperty(
name="Connect UV",
default=True
)
- def __init__(self):
- self.__impl = impl.UnlockImpl()
-
@classmethod
def poll(cls, context):
- return impl.UnlockImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ sc = context.scene
+ props = sc.muv_props.texture_lock
+ if not props.verts_orig:
+ return False
+ if not MUV_OT_TextureLock_Lock.is_ready(context):
+ return False
+ if not _is_valid_context(context):
+ return False
+ return True
def execute(self, context):
- return self.__impl.execute(self, context)
+ sc = context.scene
+ props = sc.muv_props.texture_lock
+ obj = bpy.context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ 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()
+
+ verts = [v.index for v in bm.verts if v.select]
+ verts_orig = props.verts_orig
+
+ # move UV followed by vertex coordinate
+ for vidx, v_orig in zip(verts, verts_orig):
+ if vidx != v_orig["vidx"]:
+ self.report({'ERROR'}, "Internal Error")
+ return {"CANCELLED"}
+
+ v = bm.verts[vidx]
+ link_loops = _get_link_loops(v)
+
+ result = []
+
+ for ll in link_loops:
+ ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
+ target_uv = _get_target_uv(
+ ll, uv_layer, verts_orig, v, ini_geom)
+ result.append({"l": ll["l"], "uv": target_uv})
+
+ # connect other face's UV
+ if self.connect:
+ ave = Vector((0.0, 0.0))
+ for r in result:
+ ave = ave + r["uv"]
+ ave = ave / len(result)
+ for r in result:
+ r["l"][uv_layer].uv = ave
+ else:
+ for r in result:
+ r["l"][uv_layer].uv = r["uv"]
+ v_orig["moved"] = True
+ bmesh.update_edit_mesh(obj.data)
+
+ props.verts_orig = None
+
+ return {'FINISHED'}
@BlClassRegistry()
@@ -140,19 +396,142 @@ class MUV_OT_TextureLock_Intr(bpy.types.Operator):
bl_label = "Texture Lock (Interactive mode)"
bl_description = "Internal operation for Texture Lock (Interactive mode)"
- def __init__(self):
- self.__impl = impl.IntrImpl()
+ __timer = None
@classmethod
def poll(cls, context):
- return impl.IntrImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return False
+ return _is_valid_context(context)
+
+ @classmethod
+ def is_running(cls, _):
+ return 1 if cls.__timer else 0
+
+ @classmethod
+ def handle_add(cls, ops_obj, context):
+ if cls.__timer is None:
+ cls.__timer = context.window_manager.event_timer_add(
+ 0.10, window=context.window)
+ context.window_manager.modal_handler_add(ops_obj)
@classmethod
- def is_running(cls, context):
- return impl.IntrImpl.is_running(context)
+ def handle_remove(cls, context):
+ if cls.__timer is not None:
+ context.window_manager.event_timer_remove(cls.__timer)
+ cls.__timer = None
+
+ def __init__(self):
+ self.__intr_verts_orig = []
+ self.__intr_verts = []
+
+ def __sel_verts_changed(self, context):
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ prev = set(self.__intr_verts)
+ now = set([v.index for v in bm.verts if v.select])
+
+ return prev != now
+
+ def __reinit_verts(self, context):
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ self.__intr_verts_orig = [
+ {"vidx": v.index, "vco": v.co.copy(), "moved": False}
+ for v in bm.verts if v.select]
+ self.__intr_verts = [v.index for v in bm.verts if v.select]
+
+ def __update_uv(self, context):
+ """
+ Update UV when vertex coordinates are changed
+ """
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ if not bm.loops.layers.uv:
+ self.report({'WARNING'}, "Object must have more than one UV map")
+ return
+ uv_layer = bm.loops.layers.uv.verify()
+
+ verts = [v.index for v in bm.verts if v.select]
+ verts_orig = self.__intr_verts_orig
+
+ for vidx, v_orig in zip(verts, verts_orig):
+ if vidx != v_orig["vidx"]:
+ self.report({'ERROR'}, "Internal Error")
+ return
+
+ v = bm.verts[vidx]
+ link_loops = _get_link_loops(v)
+
+ result = []
+ for ll in link_loops:
+ ini_geom = _get_ini_geom(ll, uv_layer, verts_orig, v_orig)
+ target_uv = _get_target_uv(
+ ll, uv_layer, verts_orig, v, ini_geom)
+ result.append({"l": ll["l"], "uv": target_uv})
+
+ # UV connect option is always true, because it raises
+ # unexpected behavior
+ ave = Vector((0.0, 0.0))
+ for r in result:
+ ave = ave + r["uv"]
+ ave = ave / len(result)
+ for r in result:
+ r["l"][uv_layer].uv = ave
+ v_orig["moved"] = True
+ bmesh.update_edit_mesh(obj.data)
+
+ common.redraw_all_areas()
+ self.__intr_verts_orig = [
+ {"vidx": v.index, "vco": v.co.copy(), "moved": False}
+ for v in bm.verts if v.select]
def modal(self, context, event):
- return self.__impl.modal(self, context, event)
+ if not _is_valid_context(context):
+ MUV_OT_TextureLock_Intr.handle_remove(context)
+ return {'FINISHED'}
+
+ if not MUV_OT_TextureLock_Intr.is_running(context):
+ return {'FINISHED'}
+
+ if context.area:
+ context.area.tag_redraw()
+
+ if event.type == 'TIMER':
+ if self.__sel_verts_changed(context):
+ self.__reinit_verts(context)
+ else:
+ self.__update_uv(context)
+
+ return {'PASS_THROUGH'}
+
+ def invoke(self, context, _):
+ if not _is_valid_context(context):
+ return {'CANCELLED'}
+
+ if not MUV_OT_TextureLock_Intr.is_running(context):
+ MUV_OT_TextureLock_Intr.handle_add(self, context)
+ return {'RUNNING_MODAL'}
+ else:
+ MUV_OT_TextureLock_Intr.handle_remove(context)
+
+ if context.area:
+ context.area.tag_redraw()
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/texture_projection.py b/uv_magic_uv/op/texture_projection.py
index f6a3a89f..cb7c25bb 100644
--- a/uv_magic_uv/op/texture_projection.py
+++ b/uv_magic_uv/op/texture_projection.py
@@ -23,8 +23,9 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
+from collections import namedtuple
+
import bpy
-import bgl
import bmesh
from bpy_extras import view3d_utils
from bpy.props import (
@@ -32,17 +33,118 @@ from bpy.props import (
EnumProperty,
FloatProperty,
)
+import mathutils
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import texture_projection_impl as impl
+from ..utils import compatibility as compat
+
+if compat.check_version(2, 80, 0) >= 0:
+ from ..lib import bglx as bgl
+else:
+ import bgl
+
+
+_Rect = namedtuple('Rect', 'x0 y0 x1 y1')
+_Rect2 = namedtuple('Rect2', 'x y width height')
+
+
+def get_loaded_texture_name(_, __):
+ items = [(key, key, "") for key in bpy.data.images.keys()]
+ items.append(("None", "None", ""))
+ return items
+
+
+def get_canvas(context, magnitude):
+ """
+ Get canvas to be renderred texture
+ """
+ sc = context.scene
+ prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
+
+ region_w = context.region.width
+ region_h = context.region.height
+ canvas_w = region_w - prefs.texture_projection_canvas_padding[0] * 2.0
+ canvas_h = region_h - prefs.texture_projection_canvas_padding[1] * 2.0
+
+ img = bpy.data.images[sc.muv_texture_projection_tex_image]
+ tex_w = img.size[0]
+ tex_h = img.size[1]
+
+ center_x = region_w * 0.5
+ center_y = region_h * 0.5
+
+ if sc.muv_texture_projection_adjust_window:
+ ratio_x = canvas_w / tex_w
+ ratio_y = canvas_h / tex_h
+ if sc.muv_texture_projection_apply_tex_aspect:
+ ratio = ratio_y if ratio_x > ratio_y else ratio_x
+ len_x = ratio * tex_w
+ len_y = ratio * tex_h
+ else:
+ len_x = canvas_w
+ len_y = canvas_h
+ else:
+ if sc.muv_texture_projection_apply_tex_aspect:
+ len_x = tex_w * magnitude
+ len_y = tex_h * magnitude
+ else:
+ len_x = region_w * magnitude
+ len_y = region_h * magnitude
-from ..lib import bglx
+ x0 = int(center_x - len_x * 0.5)
+ y0 = int(center_y - len_y * 0.5)
+ x1 = int(center_x + len_x * 0.5)
+ y1 = int(center_y + len_y * 0.5)
+
+ return _Rect(x0, y0, x1, y1)
+
+
+def rect_to_rect2(rect):
+ """
+ Convert Rect1 to Rect2
+ """
+
+ return _Rect2(rect.x0, rect.y0, rect.x1 - rect.x0, rect.y1 - rect.y0)
+
+
+def region_to_canvas(rg_vec, canvas):
+ """
+ Convert screen region to canvas
+ """
+
+ cv_rect = rect_to_rect2(canvas)
+ cv_vec = mathutils.Vector()
+ cv_vec.x = (rg_vec.x - cv_rect.x) / cv_rect.width
+ cv_vec.y = (rg_vec.y - cv_rect.y) / cv_rect.height
+
+ return cv_vec
+
+
+def is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "texture_projection"
@classmethod
@@ -79,7 +181,7 @@ class Properties:
scene.muv_texture_projection_tex_image = EnumProperty(
name="Image",
description="Texture Image",
- items=impl.get_loaded_texture_name
+ items=get_loaded_texture_name
)
scene.muv_texture_projection_tex_transparency = FloatProperty(
name="Transparency",
@@ -133,7 +235,7 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return False
- return impl.is_valid_context(context)
+ return is_valid_context(context)
@classmethod
def is_running(cls, _):
@@ -166,7 +268,7 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
img = bpy.data.images[sc.muv_texture_projection_tex_image]
# setup rendering region
- rect = impl.get_canvas(context, sc.muv_texture_projection_tex_magnitude)
+ rect = get_canvas(context, sc.muv_texture_projection_tex_magnitude)
positions = [
[rect.x0, rect.y0],
[rect.x0, rect.y1],
@@ -181,21 +283,35 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
]
# OpenGL configuration
- bgl.glEnable(bgl.GL_BLEND)
- bgl.glEnable(bgl.GL_TEXTURE_2D)
- bgl.glActiveTexture(bgl.GL_TEXTURE0)
- if img.bindcode:
- bind = img.bindcode
- bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
+ if compat.check_version(2, 80, 0) >= 0:
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glEnable(bgl.GL_TEXTURE_2D)
+ bgl.glActiveTexture(bgl.GL_TEXTURE0)
+ if img.bindcode:
+ bind = img.bindcode
+ bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
+ else:
+ bgl.glEnable(bgl.GL_BLEND)
+ bgl.glEnable(bgl.GL_TEXTURE_2D)
+ if img.bindcode:
+ bind = img.bindcode[0]
+ bgl.glBindTexture(bgl.GL_TEXTURE_2D, bind)
+ bgl.glTexParameteri(
+ bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MIN_FILTER, bgl.GL_LINEAR)
+ bgl.glTexParameteri(
+ bgl.GL_TEXTURE_2D, bgl.GL_TEXTURE_MAG_FILTER, bgl.GL_LINEAR)
+ bgl.glTexEnvi(
+ bgl.GL_TEXTURE_ENV, bgl.GL_TEXTURE_ENV_MODE,
+ bgl.GL_MODULATE)
# render texture
- bglx.glBegin(bglx.GL_QUADS)
- bglx.glColor4f(1.0, 1.0, 1.0,
+ bgl.glBegin(bgl.GL_QUADS)
+ bgl.glColor4f(1.0, 1.0, 1.0,
sc.muv_texture_projection_tex_transparency)
for (v1, v2), (u, v) in zip(positions, tex_coords):
- bglx.glTexCoord2f(u, v)
- bglx.glVertex2f(v1, v2)
- bglx.glEnd()
+ bgl.glTexCoord2f(u, v)
+ bgl.glVertex2f(v1, v2)
+ bgl.glEnd()
def invoke(self, context, _):
if not MUV_OT_TextureProjection.is_running(context):
@@ -227,7 +343,7 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
return True
if not MUV_OT_TextureProjection.is_running(context):
return False
- return impl.is_valid_context(context)
+ return is_valid_context(context)
def execute(self, context):
sc = context.scene
@@ -255,6 +371,9 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
return {'CANCELLED'}
uv_layer = bm.loops.layers.uv.verify()
+ if compat.check_version(2, 80, 0) < 0:
+ tex_layer = bm.faces.layers.tex.verify()
+
sel_faces = [f for f in bm.faces if f.select]
# transform 3d space to screen region
@@ -262,26 +381,30 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
view3d_utils.location_3d_to_region_2d(
region,
space.region_3d,
- world_mat @ l.vert.co)
+ compat.matmul(world_mat, l.vert.co))
for f in sel_faces for l in f.loops
]
# transform screen region to canvas
v_canvas = [
- impl.region_to_canvas(
+ region_to_canvas(
v,
- impl.get_canvas(bpy.context,
- sc.muv_texture_projection_tex_magnitude)
+ get_canvas(bpy.context,
+ sc.muv_texture_projection_tex_magnitude)
) for v in v_screen
]
- # set texture
- nodes = common.find_texture_nodes(obj)
- nodes[0].image = bpy.data.images[sc.muv_texture_projection_tex_image]
+ if compat.check_version(2, 80, 0) >= 0:
+ # set texture
+ nodes = common.find_texture_nodes(obj)
+ nodes[0].image = bpy.data.images[sc.muv_texture_projection_tex_image]
# project texture to object
i = 0
for f in sel_faces:
+ if compat.check_version(2, 80, 0) < 0:
+ f[tex_layer].image = \
+ bpy.data.images[sc.muv_texture_projection_tex_image]
for l in f.loops:
l[uv_layer].uv = v_canvas[i].to_2d()
i = i + 1
diff --git a/uv_magic_uv/op/texture_wrap.py b/uv_magic_uv/op/texture_wrap.py
index 70fb6604..c78ffed9 100644
--- a/uv_magic_uv/op/texture_wrap.py
+++ b/uv_magic_uv/op/texture_wrap.py
@@ -27,10 +27,32 @@ import bpy
from bpy.props import (
BoolProperty,
)
+import bmesh
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import texture_wrap_impl as impl
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
@@ -80,15 +102,33 @@ class MUV_OT_TextureWrap_Refer(bpy.types.Operator):
bl_description = "Refer UV"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.ReferImpl()
-
@classmethod
def poll(cls, context):
- return impl.ReferImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ props = context.scene.muv_props.texture_wrap
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+
+ if not bm.loops.layers.uv:
+ self.report({'WARNING'}, "Object must have more than one UV map")
+ return {'CANCELLED'}
+
+ sel_faces = [f for f in bm.faces if f.select]
+ if len(sel_faces) != 1:
+ self.report({'WARNING'}, "Must select only one face")
+ return {'CANCELLED'}
+
+ props.ref_face_index = sel_faces[0].index
+ props.ref_obj = obj
+
+ return {'FINISHED'}
@BlClassRegistry()
@@ -102,12 +142,153 @@ class MUV_OT_TextureWrap_Set(bpy.types.Operator):
bl_description = "Set UV"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.SetImpl()
-
@classmethod
def poll(cls, context):
- return impl.SetImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ sc = context.scene
+ props = sc.muv_props.texture_wrap
+ if not props.ref_obj:
+ return False
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ sc = context.scene
+ props = sc.muv_props.texture_wrap
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+
+ 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()
+
+ if sc.muv_texture_wrap_selseq:
+ sel_faces = []
+ for hist in bm.select_history:
+ if isinstance(hist, bmesh.types.BMFace) and hist.select:
+ sel_faces.append(hist)
+ if not sel_faces:
+ self.report({'WARNING'}, "Must select more than one face")
+ return {'CANCELLED'}
+ else:
+ sel_faces = [f for f in bm.faces if f.select]
+ if len(sel_faces) != 1:
+ self.report({'WARNING'}, "Must select only one face")
+ return {'CANCELLED'}
+
+ ref_face_index = props.ref_face_index
+ for face in sel_faces:
+ tgt_face_index = face.index
+ if ref_face_index == tgt_face_index:
+ self.report({'WARNING'}, "Must select different face")
+ return {'CANCELLED'}
+
+ if props.ref_obj != obj:
+ self.report({'WARNING'}, "Object must be same")
+ return {'CANCELLED'}
+
+ ref_face = bm.faces[ref_face_index]
+ tgt_face = bm.faces[tgt_face_index]
+
+ # get common vertices info
+ common_verts = []
+ for sl in ref_face.loops:
+ for dl in tgt_face.loops:
+ if sl.vert == dl.vert:
+ info = {"vert": sl.vert, "ref_loop": sl,
+ "tgt_loop": dl}
+ common_verts.append(info)
+ break
+
+ if len(common_verts) != 2:
+ self.report({'WARNING'},
+ "2 vertices must be shared among faces")
+ return {'CANCELLED'}
+
+ # get reference other vertices info
+ ref_other_verts = []
+ for sl in ref_face.loops:
+ for ci in common_verts:
+ if sl.vert == ci["vert"]:
+ break
+ else:
+ info = {"vert": sl.vert, "loop": sl}
+ ref_other_verts.append(info)
+
+ if not ref_other_verts:
+ self.report({'WARNING'}, "More than 1 vertex must be unshared")
+ return {'CANCELLED'}
+
+ # get reference info
+ ref_info = {}
+ cv0 = common_verts[0]["vert"].co
+ cv1 = common_verts[1]["vert"].co
+ cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
+ cuv1 = common_verts[1]["ref_loop"][uv_layer].uv
+ ov0 = ref_other_verts[0]["vert"].co
+ ouv0 = ref_other_verts[0]["loop"][uv_layer].uv
+ ref_info["vert_vdiff"] = cv1 - cv0
+ ref_info["uv_vdiff"] = cuv1 - cuv0
+ ref_info["vert_hdiff"], _ = common.diff_point_to_segment(
+ cv0, cv1, ov0)
+ ref_info["uv_hdiff"], _ = common.diff_point_to_segment(
+ cuv0, cuv1, ouv0)
+
+ # get target other vertices info
+ tgt_other_verts = []
+ for dl in tgt_face.loops:
+ for ci in common_verts:
+ if dl.vert == ci["vert"]:
+ break
+ else:
+ info = {"vert": dl.vert, "loop": dl}
+ tgt_other_verts.append(info)
+
+ if not tgt_other_verts:
+ self.report({'WARNING'}, "More than 1 vertex must be unshared")
+ return {'CANCELLED'}
+
+ # get target info
+ for info in tgt_other_verts:
+ cv0 = common_verts[0]["vert"].co
+ cv1 = common_verts[1]["vert"].co
+ cuv0 = common_verts[0]["ref_loop"][uv_layer].uv
+ ov = info["vert"].co
+ info["vert_hdiff"], x = common.diff_point_to_segment(
+ cv0, cv1, ov)
+ info["vert_vdiff"] = x - common_verts[0]["vert"].co
+
+ # calclulate factor
+ fact_h = -info["vert_hdiff"].length / \
+ ref_info["vert_hdiff"].length
+ fact_v = info["vert_vdiff"].length / \
+ ref_info["vert_vdiff"].length
+ duv_h = ref_info["uv_hdiff"] * fact_h
+ duv_v = ref_info["uv_vdiff"] * fact_v
+
+ # get target UV
+ info["target_uv"] = cuv0 + duv_h + duv_v
+
+ # apply to common UVs
+ for info in common_verts:
+ info["tgt_loop"][uv_layer].uv = \
+ info["ref_loop"][uv_layer].uv.copy()
+ # apply to other UVs
+ for info in tgt_other_verts:
+ info["loop"][uv_layer].uv = info["target_uv"]
+
+ common.debug_print("===== Target Other Vertices =====")
+ common.debug_print(tgt_other_verts)
+
+ bmesh.update_edit_mesh(obj.data)
+
+ ref_face_index = tgt_face_index
+
+ if sc.muv_texture_wrap_set_and_refer:
+ props.ref_face_index = tgt_face_index
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/transfer_uv.py b/uv_magic_uv/op/transfer_uv.py
index db05b343..25d430b9 100644
--- a/uv_magic_uv/op/transfer_uv.py
+++ b/uv_magic_uv/op/transfer_uv.py
@@ -23,25 +23,307 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
+from collections import OrderedDict
+
import bpy
import bmesh
from bpy.props import BoolProperty
from .. import common
-from ..impl import transfer_uv_impl as impl
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def _get_uv_layer(ops_obj, bm):
+ # get UV layer
+ if not bm.loops.layers.uv:
+ ops_obj.report({'WARNING'}, "Object must have more than one UV map")
+ return None
+ uv_layer = bm.loops.layers.uv.verify()
+
+ return uv_layer
+
+
+def _main_parse(ops_obj, uv_layer, sel_faces, active_face, active_face_nor):
+ all_sorted_faces = OrderedDict() # This is the main stuff
+
+ used_verts = set()
+ used_edges = set()
+
+ faces_to_parse = []
+
+ # get shared edge of two faces
+ cross_edges = []
+ for edge in active_face.edges:
+ if edge in sel_faces[0].edges and edge in sel_faces[1].edges:
+ cross_edges.append(edge)
+
+ # parse two selected faces
+ if cross_edges and len(cross_edges) == 1:
+ shared_edge = cross_edges[0]
+ vert1 = None
+ vert2 = None
+
+ dot_n = active_face_nor.normalized()
+ edge_vec_1 = (shared_edge.verts[1].co - shared_edge.verts[0].co)
+ edge_vec_len = edge_vec_1.length
+ edge_vec_1 = edge_vec_1.normalized()
+
+ af_center = active_face.calc_center_median()
+ af_vec = shared_edge.verts[0].co + (edge_vec_1 * (edge_vec_len * 0.5))
+ af_vec = (af_vec - af_center).normalized()
+
+ if af_vec.cross(edge_vec_1).dot(dot_n) > 0:
+ vert1 = shared_edge.verts[0]
+ vert2 = shared_edge.verts[1]
+ else:
+ vert1 = shared_edge.verts[1]
+ vert2 = shared_edge.verts[0]
+
+ # get active face stuff and uvs
+ face_stuff = _get_other_verts_edges(
+ active_face, vert1, vert2, shared_edge, uv_layer)
+ all_sorted_faces[active_face] = face_stuff
+ used_verts.update(active_face.verts)
+ used_edges.update(active_face.edges)
+
+ # get first selected face stuff and uvs as they share shared_edge
+ second_face = sel_faces[0]
+ if second_face is active_face:
+ second_face = sel_faces[1]
+ face_stuff = _get_other_verts_edges(
+ second_face, vert1, vert2, shared_edge, uv_layer)
+ all_sorted_faces[second_face] = face_stuff
+ used_verts.update(second_face.verts)
+ used_edges.update(second_face.edges)
+
+ # first Grow
+ faces_to_parse.append(active_face)
+ faces_to_parse.append(second_face)
+
+ else:
+ ops_obj.report({'WARNING'}, "Two faces should share one edge")
+ return None
+
+ # parse all faces
+ while True:
+ new_parsed_faces = []
+ if not faces_to_parse:
+ break
+ for face in faces_to_parse:
+ face_stuff = all_sorted_faces.get(face)
+ new_faces = _parse_faces(face, face_stuff, used_verts, used_edges,
+ all_sorted_faces, uv_layer)
+ if new_faces is None:
+ ops_obj.report({'WARNING'}, "More than 2 faces share edge")
+ return None
+
+ new_parsed_faces += new_faces
+ faces_to_parse = new_parsed_faces
+
+ return all_sorted_faces
+
+
+def _parse_faces(check_face, face_stuff, used_verts, used_edges,
+ all_sorted_faces, uv_layer):
+ """recurse faces around the new_grow only"""
+
+ new_shared_faces = []
+ for sorted_edge in face_stuff[1]:
+ shared_faces = sorted_edge.link_faces
+ if shared_faces:
+ if len(shared_faces) > 2:
+ bpy.ops.mesh.select_all(action='DESELECT')
+ for face_sel in shared_faces:
+ face_sel.select = True
+ shared_faces = []
+ return None
+
+ clear_shared_faces = _get_new_shared_faces(
+ check_face, sorted_edge, shared_faces, all_sorted_faces.keys())
+ if clear_shared_faces:
+ shared_face = clear_shared_faces[0]
+ # get vertices of the edge
+ vert1 = sorted_edge.verts[0]
+ vert2 = sorted_edge.verts[1]
+
+ common.debug_print(face_stuff[0], vert1, vert2)
+ if face_stuff[0].index(vert1) > face_stuff[0].index(vert2):
+ vert1 = sorted_edge.verts[1]
+ vert2 = sorted_edge.verts[0]
+
+ common.debug_print(shared_face.verts, vert1, vert2)
+ new_face_stuff = _get_other_verts_edges(
+ shared_face, vert1, vert2, sorted_edge, uv_layer)
+ all_sorted_faces[shared_face] = new_face_stuff
+ used_verts.update(shared_face.verts)
+ used_edges.update(shared_face.edges)
+ if common.is_debug_mode():
+ shared_face.select = True # test which faces are parsed
-__all__ = [
- 'Properties',
- 'MUV_OT_TransferUV_CopyUV',
- 'MUV_OT_TransferUV_PasteUV',
-]
+ new_shared_faces.append(shared_face)
+
+ return new_shared_faces
+
+
+def _get_new_shared_faces(orig_face, shared_edge, check_faces, used_faces):
+ shared_faces = []
+
+ for face in check_faces:
+ is_shared_edge = shared_edge in face.edges
+ not_used = face not in used_faces
+ not_orig = face is not orig_face
+ not_hide = face.hide is False
+ if is_shared_edge and not_used and not_orig and not_hide:
+ shared_faces.append(face)
+
+ return shared_faces
+
+
+def _get_other_verts_edges(face, vert1, vert2, first_edge, uv_layer):
+ face_edges = [first_edge]
+ face_verts = [vert1, vert2]
+ face_loops = []
+
+ other_edges = [edge for edge in face.edges if edge not in face_edges]
+
+ for _ in range(len(other_edges)):
+ found_edge = None
+ # get sorted verts and edges
+ for edge in other_edges:
+ if face_verts[-1] in edge.verts:
+ other_vert = edge.other_vert(face_verts[-1])
+
+ if other_vert not in face_verts:
+ face_verts.append(other_vert)
+
+ found_edge = edge
+ if found_edge not in face_edges:
+ face_edges.append(edge)
+ break
+
+ other_edges.remove(found_edge)
+
+ # get sorted uvs
+ for vert in face_verts:
+ for loop in face.loops:
+ if loop.vert is vert:
+ face_loops.append(loop[uv_layer])
+ break
+
+ return [face_verts, face_edges, face_loops]
+
+
+def _get_selected_src_faces(ops_obj, bm, uv_layer):
+ topology_copied = []
+
+ # get selected faces
+ active_face = bm.faces.active
+ sel_faces = [face for face in bm.faces if face.select]
+ if len(sel_faces) != 2:
+ ops_obj.report({'WARNING'}, "Two faces must be selected")
+ return None
+ if not active_face or active_face not in sel_faces:
+ ops_obj.report({'WARNING'}, "Two faces must be active")
+ return None
+
+ # parse all faces according to selection
+ active_face_nor = active_face.normal.copy()
+ all_sorted_faces = _main_parse(ops_obj, uv_layer, sel_faces, active_face,
+ active_face_nor)
+
+ if all_sorted_faces:
+ for face_data in all_sorted_faces.values():
+ edges = face_data[1]
+ uv_loops = face_data[2]
+ uvs = [l.uv.copy() for l in uv_loops]
+ pin_uvs = [l.pin_uv for l in uv_loops]
+ seams = [e.seam for e in edges]
+ topology_copied.append([uvs, pin_uvs, seams])
+ else:
+ return None
+
+ return topology_copied
+
+
+def _paste_uv(ops_obj, bm, uv_layer, src_faces, invert_normals, copy_seams):
+ # get selection history
+ all_sel_faces = [e for e in bm.select_history
+ if isinstance(e, bmesh.types.BMFace) and e.select]
+ if len(all_sel_faces) % 2 != 0:
+ ops_obj.report({'WARNING'}, "Two faces must be selected")
+ return -1
+
+ # parse selection history
+ for i, _ in enumerate(all_sel_faces):
+ 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 invert_normals:
+ active_face_nor.negate()
+ all_sorted_faces = _main_parse(ops_obj, 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(src_faces):
+ ops_obj.report({'WARNING'},
+ "Mesh has different amount of faces")
+ return -1
+
+ for j, face_data in enumerate(all_sorted_faces.values()):
+ copied_data = src_faces[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
+ ops_obj.report({'WARNING'},
+ "Face have different amount of vertices")
+ return 0
+
+ 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 copy_seams:
+ edge.seam = copied_data[2][k]
+ else:
+ return -1
+
+ return 0
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "transfer_uv"
@classmethod
@@ -91,19 +373,20 @@ class MUV_OT_TransferUV_CopyUV(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return True
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
props = context.scene.muv_props.transfer_uv
- active_obj = context.active_object
+ active_obj = compat.get_active_object(context)
bm = bmesh.from_edit_mesh(active_obj.data)
- bm.faces.ensure_lookup_table()
+ if compat.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
- uv_layer = impl.get_uv_layer(self, bm)
+ uv_layer = _get_uv_layer(self, bm)
if uv_layer is None:
return {'CANCELLED'}
- faces = impl.get_selected_src_faces(self, bm, uv_layer)
+ faces = _get_selected_src_faces(self, bm, uv_layer)
if faces is None:
return {'CANCELLED'}
props.topology_copied = faces
@@ -114,6 +397,7 @@ class MUV_OT_TransferUV_CopyUV(bpy.types.Operator):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
"""
Operation class: Transfer UV paste
@@ -125,12 +409,12 @@ class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
bl_description = "Transfer UV Paste UV (Topological based paste)"
bl_options = {'REGISTER', 'UNDO'}
- invert_normals: BoolProperty(
+ invert_normals = BoolProperty(
name="Invert Normals",
description="Invert Normals",
default=False
)
- copy_seams: BoolProperty(
+ copy_seams = BoolProperty(
name="Copy Seams",
description="Copy Seams",
default=True
@@ -145,24 +429,29 @@ class MUV_OT_TransferUV_PasteUV(bpy.types.Operator):
props = sc.muv_props.transfer_uv
if not props.topology_copied:
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
props = context.scene.muv_props.transfer_uv
- active_obj = context.active_object
+ active_obj = compat.get_active_object(context)
bm = bmesh.from_edit_mesh(active_obj.data)
- bm.faces.ensure_lookup_table()
+ if compat.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
# get UV layer
- uv_layer = impl.get_uv_layer(self, bm)
+ uv_layer = _get_uv_layer(self, bm)
if uv_layer is None:
return {'CANCELLED'}
- ret = impl.paste_uv(self, bm, uv_layer, props.topology_copied,
- self.invert_normals, self.copy_seams)
+ ret = _paste_uv(self, bm, uv_layer, props.topology_copied,
+ self.invert_normals, self.copy_seams)
if ret:
return {'CANCELLED'}
bmesh.update_edit_mesh(active_obj.data)
+ if compat.check_version(2, 80, 0) < 0:
+ if self.copy_seams:
+ active_obj.data.show_edge_seams = True
+
return {'FINISHED'}
diff --git a/uv_magic_uv/op/unwrap_constraint.py b/uv_magic_uv/op/unwrap_constraint.py
index df16f783..89727160 100644
--- a/uv_magic_uv/op/unwrap_constraint.py
+++ b/uv_magic_uv/op/unwrap_constraint.py
@@ -27,10 +27,33 @@ from bpy.props import (
EnumProperty,
FloatProperty,
)
+import bmesh
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import unwrap_constraint_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
@PropertyClassRegistry()
@@ -63,6 +86,7 @@ class _Properties:
@BlClassRegistry(legacy=True)
+@compat.make_annotations
class MUV_OT_UnwrapConstraint(bpy.types.Operator):
"""
Operation class: Unwrap with constrain UV coordinate
@@ -74,7 +98,7 @@ class MUV_OT_UnwrapConstraint(bpy.types.Operator):
bl_options = {'REGISTER', 'UNDO'}
# property for original unwrap
- method: EnumProperty(
+ method = EnumProperty(
name="Method",
description="Unwrapping method",
items=[
@@ -82,20 +106,20 @@ class MUV_OT_UnwrapConstraint(bpy.types.Operator):
('CONFORMAL', 'Conformal', 'Conformal')
],
default='ANGLE_BASED')
- fill_holes: BoolProperty(
+ fill_holes = BoolProperty(
name="Fill Holes",
description="Virtual fill holes in meshes before unwrapping",
default=True)
- correct_aspect: BoolProperty(
+ correct_aspect = BoolProperty(
name="Correct Aspect",
description="Map UVs taking image aspect ratio into account",
default=True)
- use_subsurf_data: BoolProperty(
+ use_subsurf_data = BoolProperty(
name="Use Subsurf Modifier",
description="""Map UVs taking vertex position after subsurf
into account""",
default=False)
- margin: FloatProperty(
+ margin = FloatProperty(
name="Margin",
description="Space between islands",
max=1.0,
@@ -103,23 +127,60 @@ class MUV_OT_UnwrapConstraint(bpy.types.Operator):
default=0.001)
# property for this operation
- u_const: BoolProperty(
+ u_const = BoolProperty(
name="U-Constraint",
description="Keep UV U-axis coordinate",
default=False
)
- v_const: BoolProperty(
+ v_const = BoolProperty(
name="V-Constraint",
description="Keep UV V-axis coordinate",
default=False
)
- def __init__(self):
- self.__impl = impl.UnwrapConstraintImpl()
-
@classmethod
def poll(cls, context):
- return impl.UnwrapConstraintImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+
+ # bpy.ops.uv.unwrap() makes one UV map at least
+ 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()
+
+ # get original UV coordinate
+ faces = [f for f in bm.faces if f.select]
+ uv_list = []
+ for f in faces:
+ uvs = [l[uv_layer].uv.copy() for l in f.loops]
+ uv_list.append(uvs)
+
+ # unwrap
+ bpy.ops.uv.unwrap(
+ method=self.method,
+ fill_holes=self.fill_holes,
+ correct_aspect=self.correct_aspect,
+ use_subsurf_data=self.use_subsurf_data,
+ margin=self.margin)
+
+ # when U/V-Constraint is checked, revert original coordinate
+ for f, uvs in zip(faces, uv_list):
+ for l, uv in zip(f.loops, uvs):
+ if self.u_const:
+ l[uv_layer].uv.x = uv.x
+ if self.v_const:
+ l[uv_layer].uv.y = uv.y
+
+ # update mesh
+ bmesh.update_edit_mesh(obj.data)
+
+ return {'FINISHED'}
diff --git a/uv_magic_uv/op/uv_bounding_box.py b/uv_magic_uv/op/uv_bounding_box.py
index 82cdea45..4839934b 100644
--- a/uv_magic_uv/op/uv_bounding_box.py
+++ b/uv_magic_uv/op/uv_bounding_box.py
@@ -27,7 +27,6 @@ from enum import IntEnum
import math
import bpy
-import bgl
import mathutils
import bmesh
from bpy.props import BoolProperty, EnumProperty
@@ -35,14 +34,40 @@ from bpy.props import BoolProperty, EnumProperty
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import uv_bounding_box_impl as impl
+from ..utils import compatibility as compat
-from ..lib import bglx
+if compat.check_version(2, 80, 0) >= 0:
+ from ..lib import bglx as bgl
+else:
+ import bgl
MAX_VALUE = 100000.0
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
+
+
@PropertyClassRegistry()
class _Properties:
idname = "uv_bounding_box"
@@ -166,7 +191,7 @@ class RotationCommand(CommandBase):
mti = mathutils.Matrix.Translation((-self.__cx, -self.__cy, 0.0))
mr = mathutils.Matrix.Rotation(angle, 4, 'Z')
mt = mathutils.Matrix.Translation((self.__cx, self.__cy, 0.0))
- return mt @ mr @ mti
+ return compat.matmul(compat.matmul(mt, mr), mti)
def set(self, x, y):
self.__x = x
@@ -191,7 +216,7 @@ class ScalingCommand(CommandBase):
self.__dir_y = dir_y # direction of scaling y
self.__mat = mat
# initial origin of scaling = M(to original transform) * (ox, oy)
- iov = mat @ mathutils.Vector((ox, oy, 0.0))
+ iov = compat.matmul(mat, mathutils.Vector((ox, oy, 0.0)))
self.__iox = iov.x # initial origin of scaling X
self.__ioy = iov.y # initial origin of scaling y
@@ -205,11 +230,11 @@ class ScalingCommand(CommandBase):
mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
# every point must be transformed to origin
- t = m @ mathutils.Vector((self.__ix, self.__iy, 0.0))
+ t = compat.matmul(m, mathutils.Vector((self.__ix, self.__iy, 0.0)))
tix, tiy = t.x, t.y
- t = m @ mathutils.Vector((self.__ox, self.__oy, 0.0))
+ t = compat.matmul(m, mathutils.Vector((self.__ox, self.__oy, 0.0)))
tox, toy = t.x, t.y
- t = m @ mathutils.Vector((self.__x, self.__y, 0.0))
+ t = compat.matmul(m, mathutils.Vector((self.__x, self.__y, 0.0)))
tx, ty = t.x, t.y
ms = mathutils.Matrix()
ms.identity()
@@ -217,7 +242,8 @@ class ScalingCommand(CommandBase):
ms[0][0] = (tx - tox) * self.__dir_x / (tix - tox)
if self.__dir_y == 1:
ms[1][1] = (ty - toy) * self.__dir_y / (tiy - toy)
- return mi @ mto @ ms @ mtoi @ m
+ return compat.matmul(compat.matmul(compat.matmul(
+ compat.matmul(mi, mto), ms), mtoi), m)
def set(self, x, y):
self.__x = x
@@ -240,7 +266,7 @@ class UniformScalingCommand(CommandBase):
self.__oy = oy # origin of scaling y
self.__mat = mat
# initial origin of scaling = M(to original transform) * (ox, oy)
- iov = mat @ mathutils.Vector((ox, oy, 0.0))
+ iov = compat.matmul(mat, mathutils.Vector((ox, oy, 0.0)))
self.__iox = iov.x # initial origin of scaling x
self.__ioy = iov.y # initial origin of scaling y
self.__dir_x = 1
@@ -256,11 +282,11 @@ class UniformScalingCommand(CommandBase):
mtoi = mathutils.Matrix.Translation((-self.__iox, -self.__ioy, 0.0))
mto = mathutils.Matrix.Translation((self.__iox, self.__ioy, 0.0))
# every point must be transformed to origin
- t = m @ mathutils.Vector((self.__ix, self.__iy, 0.0))
+ t = compat.matmul(m, mathutils.Vector((self.__ix, self.__iy, 0.0)))
tix, tiy = t.x, t.y
- t = m @ mathutils.Vector((self.__ox, self.__oy, 0.0))
+ t = compat.matmul(m, mathutils.Vector((self.__ox, self.__oy, 0.0)))
tox, toy = t.x, t.y
- t = m @ mathutils.Vector((self.__x, self.__y, 0.0))
+ t = compat.matmul(m, mathutils.Vector((self.__x, self.__y, 0.0)))
tx, ty = t.x, t.y
ms = mathutils.Matrix()
ms.identity()
@@ -281,7 +307,8 @@ class UniformScalingCommand(CommandBase):
ms[0][0] = sr * self.__dir_x
ms[1][1] = sr * self.__dir_y
- return mi @ mto @ ms @ mtoi @ m
+ return compat.matmul(compat.matmul(compat.matmul(
+ compat.matmul(mi, mto), ms), mtoi), m)
def set(self, x, y):
self.__x = x
@@ -305,7 +332,7 @@ class CommandExecuter:
mat.identity()
for i, cmd in enumerate(self.__cmd_list):
if begin <= i and (end == -1 or i <= end):
- mat = cmd.to_matrix() @ mat
+ mat = compat.matmul(cmd.to_matrix(), mat)
return mat
def undo_size(self):
@@ -402,7 +429,7 @@ class StateNone(StateBase):
"""
Update state
"""
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+ prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
cp_react_size = prefs.uv_bounding_box_cp_react_size
is_uscaling = context.scene.muv_uv_bounding_box_uniform_scaling
if (event.type == 'LEFTMOUSE') and (event.value == 'PRESS'):
@@ -602,7 +629,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
@classmethod
def is_running(cls, _):
@@ -634,7 +661,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
"""
Draw control point
"""
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+ prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
cp_size = prefs.uv_bounding_box_cp_size
offset = cp_size / 2
verts = [
@@ -644,11 +671,11 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
[pos.x + offset, pos.y - offset]
]
bgl.glEnable(bgl.GL_BLEND)
- bglx.glBegin(bglx.GL_QUADS)
- bglx.glColor4f(1.0, 1.0, 1.0, 1.0)
+ bgl.glBegin(bgl.GL_QUADS)
+ bgl.glColor4f(1.0, 1.0, 1.0, 1.0)
for (x, y) in verts:
- bglx.glVertex2f(x, y)
- bglx.glEnd()
+ bgl.glVertex2f(x, y)
+ bgl.glEnd()
@classmethod
def draw_bb(cls, _, context):
@@ -660,7 +687,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
if not MUV_OT_UVBoundingBox.is_running(context):
return
- if not impl.is_valid_context(context):
+ if not _is_valid_context(context):
return
for cp in props.ctrl_points:
@@ -747,7 +774,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
lidx = info[1]
uv = info[2]
v = mathutils.Vector((uv.x, uv.y, 0.0))
- av = trans_mat @ v
+ av = compat.matmul(trans_mat, v)
bm.faces[fidx].loops[lidx][uv_layer].uv = mathutils.Vector(
(av.x, av.y))
bmesh.update_edit_mesh(obj.data)
@@ -756,7 +783,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
"""
Update control point
"""
- return [trans_mat @ cp for cp in ctrl_points_ini]
+ return [compat.matmul(trans_mat, cp) for cp in ctrl_points_ini]
def modal(self, context, event):
props = context.scene.muv_props.uv_bounding_box
@@ -765,7 +792,7 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
if not MUV_OT_UVBoundingBox.is_running(context):
return {'FINISHED'}
- if not impl.is_valid_context(context):
+ if not _is_valid_context(context):
MUV_OT_UVBoundingBox.handle_remove(context)
return {'FINISHED'}
@@ -774,8 +801,8 @@ class MUV_OT_UVBoundingBox(bpy.types.Operator):
'UI',
'TOOLS',
]
- if not common.mouse_on_area_legacy(event, 'IMAGE_EDITOR') or \
- common.mouse_on_regions_legacy(event, 'IMAGE_EDITOR', region_types):
+ if not common.mouse_on_area(event, 'IMAGE_EDITOR') or \
+ common.mouse_on_regions(event, 'IMAGE_EDITOR', region_types):
return {'PASS_THROUGH'}
if event.type == 'TIMER':
diff --git a/uv_magic_uv/op/uv_inspection.py b/uv_magic_uv/op/uv_inspection.py
index 63d73fdf..0978158d 100644
--- a/uv_magic_uv/op/uv_inspection.py
+++ b/uv_magic_uv/op/uv_inspection.py
@@ -24,15 +24,60 @@ __version__ = "5.2"
__date__ = "17 Nov 2018"
import bpy
-import bgl
from bpy.props import BoolProperty, EnumProperty
+import bmesh
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import uv_inspection_impl as impl
+from ..utils import compatibility as compat
-from ..lib import bglx
+if compat.check_version(2, 80, 0) >= 0:
+ from ..lib import bglx as bgl
+else:
+ import bgl
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # 'IMAGE_EDITOR' and 'VIEW_3D' space is allowed to execute.
+ # If 'View_3D' space is not allowed, you can't find option in Tool-Shelf
+ # after the execution
+ for space in context.area.spaces:
+ if (space.type == 'IMAGE_EDITOR') or (space.type == 'VIEW_3D'):
+ break
+ else:
+ return False
+
+ return True
+
+
+def _update_uvinsp_info(context):
+ sc = context.scene
+ props = sc.muv_props.uv_inspection
+
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.faces.ensure_lookup_table()
+ uv_layer = bm.loops.layers.uv.verify()
+
+ if context.tool_settings.use_uv_select_sync:
+ sel_faces = [f for f in bm.faces]
+ else:
+ sel_faces = [f for f in bm.faces if f.select]
+ props.overlapped_info = common.get_overlapped_uv_info(
+ bm, sel_faces, uv_layer, sc.muv_uv_inspection_show_mode)
+ props.flipped_info = common.get_flipped_uv_info(sel_faces, uv_layer)
@PropertyClassRegistry()
@@ -117,7 +162,7 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
@classmethod
def is_running(cls, _):
@@ -141,7 +186,7 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
def draw(_, context):
sc = context.scene
props = sc.muv_props.uv_inspection
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+ prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
if not MUV_OT_UVInspection_Render.is_running(context):
return
@@ -155,20 +200,20 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
for info in props.overlapped_info:
if sc.muv_uv_inspection_show_mode == 'PART':
for poly in info["polygons"]:
- bglx.glBegin(bglx.GL_TRIANGLE_FAN)
- bglx.glColor4f(color[0], color[1], color[2], color[3])
+ bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+ bgl.glColor4f(color[0], color[1], color[2], color[3])
for uv in poly:
x, y = context.region.view2d.view_to_region(
uv.x, uv.y)
- bglx.glVertex2f(x, y)
- bglx.glEnd()
+ bgl.glVertex2f(x, y)
+ bgl.glEnd()
elif sc.muv_uv_inspection_show_mode == 'FACE':
- bglx.glBegin(bglx.GL_TRIANGLE_FAN)
- bglx.glColor4f(color[0], color[1], color[2], color[3])
+ bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+ bgl.glColor4f(color[0], color[1], color[2], color[3])
for uv in info["subject_uvs"]:
x, y = context.region.view2d.view_to_region(uv.x, uv.y)
- bglx.glVertex2f(x, y)
- bglx.glEnd()
+ bgl.glVertex2f(x, y)
+ bgl.glEnd()
# render flipped UV
if sc.muv_uv_inspection_show_flipped:
@@ -176,26 +221,26 @@ class MUV_OT_UVInspection_Render(bpy.types.Operator):
for info in props.flipped_info:
if sc.muv_uv_inspection_show_mode == 'PART':
for poly in info["polygons"]:
- bglx.glBegin(bglx.GL_TRIANGLE_FAN)
- bglx.glColor4f(color[0], color[1], color[2], color[3])
+ bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+ bgl.glColor4f(color[0], color[1], color[2], color[3])
for uv in poly:
x, y = context.region.view2d.view_to_region(
uv.x, uv.y)
- bglx.glVertex2f(x, y)
- bglx.glEnd()
+ bgl.glVertex2f(x, y)
+ bgl.glEnd()
elif sc.muv_uv_inspection_show_mode == 'FACE':
- bglx.glBegin(bglx.GL_TRIANGLE_FAN)
- bglx.glColor4f(color[0], color[1], color[2], color[3])
+ bgl.glBegin(bgl.GL_TRIANGLE_FAN)
+ bgl.glColor4f(color[0], color[1], color[2], color[3])
for uv in info["uvs"]:
x, y = context.region.view2d.view_to_region(uv.x, uv.y)
- bglx.glVertex2f(x, y)
- bglx.glEnd()
+ bgl.glVertex2f(x, y)
+ bgl.glEnd()
bgl.glDisable(bgl.GL_BLEND)
def invoke(self, context, _):
if not MUV_OT_UVInspection_Render.is_running(context):
- impl.update_uvinsp_info(context)
+ _update_uvinsp_info(context)
MUV_OT_UVInspection_Render.handle_add(self, context)
else:
MUV_OT_UVInspection_Render.handle_remove()
@@ -224,10 +269,10 @@ class MUV_OT_UVInspection_Update(bpy.types.Operator):
return True
if not MUV_OT_UVInspection_Render.is_running(context):
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
- impl.update_uvinsp_info(context)
+ _update_uvinsp_info(context)
if context.area:
context.area.tag_redraw()
diff --git a/uv_magic_uv/op/uv_sculpt.py b/uv_magic_uv/op/uv_sculpt.py
index cc1c0575..7dc1b843 100644
--- a/uv_magic_uv/op/uv_sculpt.py
+++ b/uv_magic_uv/op/uv_sculpt.py
@@ -41,9 +41,46 @@ from bpy.props import (
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import uv_sculpt_impl as impl
+from ..utils import compatibility as compat
-from ..lib import bglx
+
+if compat.check_version(2, 80, 0) >= 0:
+ from ..lib import bglx as bgl
+else:
+ import bgl
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def _get_strength(p, len_, factor):
+ f = factor
+
+ if p > len_:
+ return 0.0
+
+ if p < 0.0:
+ return f
+
+ return (len_ - p) * f / len_
@PropertyClassRegistry()
@@ -150,7 +187,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return False
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
@classmethod
def is_running(cls, _):
@@ -180,7 +217,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
@classmethod
def draw_brush(cls, obj, context):
sc = context.scene
- prefs = context.user_preferences.addons["uv_magic_uv"].preferences
+ prefs = compat.get_user_preferences(context).addons["uv_magic_uv"].preferences
num_segment = 180
theta = 2 * pi / num_segment
@@ -188,19 +225,19 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
fact_r = cos(theta)
color = prefs.uv_sculpt_brush_color
- bglx.glBegin(bglx.GL_LINE_STRIP)
- bglx.glColor4f(color[0], color[1], color[2], color[3])
+ bgl.glBegin(bgl.GL_LINE_STRIP)
+ bgl.glColor4f(color[0], color[1], color[2], color[3])
x = sc.muv_uv_sculpt_radius * cos(0.0)
y = sc.muv_uv_sculpt_radius * sin(0.0)
for _ in range(num_segment):
- bglx.glVertex2f(x + obj.current_mco.x, y + obj.current_mco.y)
+ bgl.glVertex2f(x + obj.current_mco.x, y + obj.current_mco.y)
tx = -y
ty = x
x = x + tx * fact_t
y = y + ty * fact_t
x = x * fact_r
y = y * fact_r
- bglx.glEnd()
+ bgl.glEnd()
def __init__(self):
self.__loop_info = []
@@ -226,7 +263,8 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
continue
for i, l in enumerate(f.loops):
loc_2d = view3d_utils.location_3d_to_region_2d(
- region, space.region_3d, world_mat @ l.vert.co)
+ region, space.region_3d,
+ compat.matmul(world_mat, l.vert.co))
diff = loc_2d - self.__initial_mco
if diff.length < sc.muv_uv_sculpt_radius:
info = {
@@ -235,7 +273,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
"initial_vco": l.vert.co.copy(),
"initial_vco_2d": loc_2d,
"initial_uv": l[uv_layer].uv.copy(),
- "strength": impl.get_strength(
+ "strength": _get_strength(
diff.length, sc.muv_uv_sculpt_radius,
sc.muv_uv_sculpt_strength)
}
@@ -263,7 +301,8 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
continue
for i, l in enumerate(f.loops):
loc_2d = view3d_utils.location_3d_to_region_2d(
- region, space.region_3d, world_mat @ l.vert.co)
+ region, space.region_3d,
+ compat.matmul(world_mat, l.vert.co))
diff = loc_2d - self.__initial_mco
if diff.length < sc.muv_uv_sculpt_radius:
info = {
@@ -272,7 +311,7 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
"initial_vco": l.vert.co.copy(),
"initial_vco_2d": loc_2d,
"initial_uv": l[uv_layer].uv.copy(),
- "strength": impl.get_strength(
+ "strength": _get_strength(
diff.length, sc.muv_uv_sculpt_radius,
sc.muv_uv_sculpt_strength)
}
@@ -287,8 +326,8 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
mco)
ray_tgt = ray_orig + ray_vec * 1000000.0
mwi = world_mat.inverted()
- ray_orig_obj = mwi @ ray_orig
- ray_tgt_obj = mwi @ ray_tgt
+ ray_orig_obj = compat.matmul(mwi, ray_orig)
+ ray_tgt_obj = compat.matmul(mwi, ray_tgt)
ray_dir_obj = ray_tgt_obj - ray_orig_obj
ray_dir_obj.normalize()
tree = BVHTree.FromBMesh(bm)
@@ -354,14 +393,15 @@ class MUV_OT_UVSculpt(bpy.types.Operator):
continue
for i, l in enumerate(f.loops):
loc_2d = view3d_utils.location_3d_to_region_2d(
- region, space.region_3d, world_mat @ l.vert.co)
+ region, space.region_3d,
+ compat.matmul(world_mat, l.vert.co))
diff = loc_2d - self.__initial_mco
if diff.length >= sc.muv_uv_sculpt_radius:
continue
db = vert_db[l.vert]
- strength = impl.get_strength(diff.length,
- sc.muv_uv_sculpt_radius,
- sc.muv_uv_sculpt_strength)
+ strength = _get_strength(diff.length,
+ sc.muv_uv_sculpt_radius,
+ sc.muv_uv_sculpt_strength)
base = (1.0 - strength) * l[uv_layer].uv
if sc.muv_uv_sculpt_relax_method == 'HC':
diff --git a/uv_magic_uv/op/uvw.py b/uv_magic_uv/op/uvw.py
index c97e0e04..9b44100c 100644
--- a/uv_magic_uv/op/uvw.py
+++ b/uv_magic_uv/op/uvw.py
@@ -23,6 +23,8 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
+from math import sin, cos, pi
+
import bpy
import bmesh
from bpy.props import (
@@ -30,22 +32,145 @@ from bpy.props import (
FloatVectorProperty,
BoolProperty
)
+from mathutils import Vector
from .. import common
-from ..impl import uvw_impl as impl
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def _get_uv_layer(ops_obj, bm, assign_uvmap):
+ # get UV layer
+ if not bm.loops.layers.uv:
+ if assign_uvmap:
+ bm.loops.layers.uv.new()
+ else:
+ ops_obj.report({'WARNING'},
+ "Object must have more than one UV map")
+ return None
+ uv_layer = bm.loops.layers.uv.verify()
+
+ return uv_layer
+
+
+def _apply_box_map(bm, uv_layer, size, offset, rotation, tex_aspect):
+ scale = 1.0 / size
+
+ sx = 1.0 * scale
+ sy = 1.0 * scale
+ sz = 1.0 * scale
+ ofx = offset[0]
+ ofy = offset[1]
+ ofz = offset[2]
+ rx = rotation[0] * pi / 180.0
+ ry = rotation[1] * pi / 180.0
+ rz = rotation[2] * pi / 180.0
+ aspect = 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))
+
+
+def _apply_planer_map(bm, uv_layer, size, offset, rotation, tex_aspect):
+ scale = 1.0 / size
+
+ sx = 1.0 * scale
+ sy = 1.0 * scale
+ ofx = offset[0]
+ ofy = offset[1]
+ rz = rotation * pi / 180.0
+ aspect = 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:
+ if common.check_version(2, 80, 0) >= 0:
+ # pylint: disable=E0001
+ co = q @ l.vert.co
+ else:
+ 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
-__all__ = [
- 'Properties',
- 'MUV_OT_UVW_BoxMap',
- 'MUV_OT_UVW_BestPlanerMap',
-]
+ l[uv_layer].uv = Vector((u, v))
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "uvw"
@classmethod
@@ -68,32 +193,33 @@ class Properties:
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_UVW_BoxMap(bpy.types.Operator):
bl_idname = "uv.muv_uvw_operator_box_map"
bl_label = "Box Map"
bl_options = {'REGISTER', 'UNDO'}
- size: FloatProperty(
+ size = FloatProperty(
name="Size",
default=1.0,
precision=4
)
- rotation: FloatVectorProperty(
+ rotation = FloatVectorProperty(
name="XYZ Rotation",
size=3,
default=(0.0, 0.0, 0.0)
)
- offset: FloatVectorProperty(
+ offset = FloatVectorProperty(
name="XYZ Offset",
size=3,
default=(0.0, 0.0, 0.0)
)
- tex_aspect: FloatProperty(
+ tex_aspect = FloatProperty(
name="Texture Aspect",
default=1.0,
precision=4
)
- assign_uvmap: BoolProperty(
+ assign_uvmap = BoolProperty(
name="Assign UVMap",
description="Assign UVMap when no UVmaps are available",
default=True
@@ -104,7 +230,7 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return True
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
obj = context.active_object
@@ -113,43 +239,44 @@ class MUV_OT_UVW_BoxMap(bpy.types.Operator):
bm.faces.ensure_lookup_table()
# get UV layer
- uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
+ uv_layer = _get_uv_layer(self, bm, self.assign_uvmap)
if not uv_layer:
return {'CANCELLED'}
- impl.apply_box_map(bm, uv_layer, self.size, self.offset,
- self.rotation, self.tex_aspect)
+ _apply_box_map(bm, uv_layer, self.size, self.offset, self.rotation,
+ self.tex_aspect)
bmesh.update_edit_mesh(obj.data)
return {'FINISHED'}
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
bl_idname = "uv.muv_uvw_operator_best_planer_map"
bl_label = "Best Planer Map"
bl_options = {'REGISTER', 'UNDO'}
- size: FloatProperty(
+ size = FloatProperty(
name="Size",
default=1.0,
precision=4
)
- rotation: FloatProperty(
+ rotation = FloatProperty(
name="XY Rotation",
default=0.0
)
- offset: FloatVectorProperty(
+ offset = FloatVectorProperty(
name="XY Offset",
size=2,
default=(0.0, 0.0)
)
- tex_aspect: FloatProperty(
+ tex_aspect = FloatProperty(
name="Texture Aspect",
default=1.0,
precision=4
)
- assign_uvmap: BoolProperty(
+ assign_uvmap = BoolProperty(
name="Assign UVMap",
description="Assign UVMap when no UVmaps are available",
default=True
@@ -160,7 +287,7 @@ class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
# we can not get area/space/region from console
if common.is_console_mode():
return True
- return impl.is_valid_context(context)
+ return _is_valid_context(context)
def execute(self, context):
obj = context.active_object
@@ -169,12 +296,12 @@ class MUV_OT_UVW_BestPlanerMap(bpy.types.Operator):
bm.faces.ensure_lookup_table()
# get UV layer
- uv_layer = impl.get_uv_layer(self, bm, self.assign_uvmap)
+ uv_layer = _get_uv_layer(self, bm, self.assign_uvmap)
if not uv_layer:
return {'CANCELLED'}
- impl.apply_planer_map(bm, uv_layer, self.size, self.offset,
- self.rotation, self.tex_aspect)
+ _apply_planer_map(bm, uv_layer, self.size, self.offset, self.rotation,
+ self.tex_aspect)
bmesh.update_edit_mesh(obj.data)
diff --git a/uv_magic_uv/op/world_scale_uv.py b/uv_magic_uv/op/world_scale_uv.py
index a957d5d4..ae46e4a9 100644
--- a/uv_magic_uv/op/world_scale_uv.py
+++ b/uv_magic_uv/op/world_scale_uv.py
@@ -23,6 +23,7 @@ __status__ = "production"
__version__ = "5.2"
__date__ = "17 Nov 2018"
+from math import sqrt
import bpy
from bpy.props import (
@@ -31,14 +32,153 @@ from bpy.props import (
IntVectorProperty,
BoolProperty,
)
+import bmesh
+from mathutils import Vector
+from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
-from ..impl import world_scale_uv_impl as impl
+from ..utils import compatibility as compat
+
+
+def _is_valid_context(context):
+ obj = context.object
+
+ # only edit mode is allowed to execute
+ if obj is None:
+ return False
+ if obj.type != 'MESH':
+ return False
+ if context.object.mode != 'EDIT':
+ return False
+
+ # only 'VIEW_3D' space is allowed to execute
+ for space in context.area.spaces:
+ if space.type == 'VIEW_3D':
+ break
+ else:
+ return False
+
+ return True
+
+
+def _measure_wsuv_info(obj, tex_size=None):
+ mesh_area = common.measure_mesh_area(obj)
+ uv_area = common.measure_uv_area(obj, tex_size)
+
+ if not uv_area:
+ return None, mesh_area, None
+
+ if mesh_area == 0.0:
+ density = 0.0
+ else:
+ density = sqrt(uv_area) / sqrt(mesh_area)
+
+ return uv_area, mesh_area, density
+
+
+def _apply(obj, origin, factor):
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ sel_faces = [f for f in bm.faces if f.select]
+
+ uv_layer = bm.loops.layers.uv.verify()
+
+ # calculate origin
+ if 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 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 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 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 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 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 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 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 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)
@PropertyClassRegistry()
-class Properties:
+class _Properties:
idname = "world_scale_uv"
@classmethod
@@ -140,18 +280,35 @@ class MUV_OT_WorldScaleUV_Measure(bpy.types.Operator):
bl_description = "Measure face size for scale calculation"
bl_options = {'REGISTER', 'UNDO'}
- def __init__(self):
- self.__impl = impl.MeasureImpl()
-
@classmethod
def poll(cls, context):
- return impl.MeasureImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ sc = context.scene
+ obj = context.active_object
+
+ uv_area, mesh_area, density = _measure_wsuv_info(obj)
+ if not uv_area:
+ self.report({'WARNING'},
+ "Object must have more than one UV map and texture")
+ return {'CANCELLED'}
+
+ sc.muv_world_scale_uv_src_uv_area = uv_area
+ sc.muv_world_scale_uv_src_mesh_area = mesh_area
+ sc.muv_world_scale_uv_src_density = density
+
+ self.report({'INFO'}, "UV Area: {0}, Mesh Area: {1}, Texel Density: {2}"
+ .format(uv_area, mesh_area, density))
+
+ return {'FINISHED'}
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
"""
Operation class: Apply scaled UV (Manual)
@@ -162,20 +319,20 @@ class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
bl_description = "Apply scaled UV based on user specification"
bl_options = {'REGISTER', 'UNDO'}
- tgt_density: FloatProperty(
+ tgt_density = FloatProperty(
name="Density",
description="Target Texel Density",
default=1.0,
min=0.0
)
- tgt_texture_size: IntVectorProperty(
+ tgt_texture_size = IntVectorProperty(
name="Texture Size",
size=2,
min=1,
soft_max=10240,
default=(1024, 1024),
)
- origin: EnumProperty(
+ origin = EnumProperty(
name="Origin",
description="Aspect Origin",
items=[
@@ -192,31 +349,64 @@ class MUV_OT_WorldScaleUV_ApplyManual(bpy.types.Operator):
],
default='CENTER'
)
- show_dialog: BoolProperty(
+ show_dialog = BoolProperty(
name="Show Diaglog Menu",
description="Show dialog menu if true",
default=True,
options={'HIDDEN', 'SKIP_SAVE'}
)
- def __init__(self):
- self.__impl = impl.ApplyManualImpl()
-
@classmethod
def poll(cls, context):
- return impl.ApplyManualImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
+
+ def __apply_manual(self, context):
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ tex_size = self.tgt_texture_size
+ uv_area, _, density = _measure_wsuv_info(obj, tex_size)
+ if not uv_area:
+ self.report({'WARNING'}, "Object must have more than one UV map")
+ return {'CANCELLED'}
+
+ tgt_density = self.tgt_density
+ factor = tgt_density / density
+
+ _apply(context.active_object, self.origin, factor)
+ self.report({'INFO'}, "Scaling factor: {0}".format(factor))
+
+ return {'FINISHED'}
- def draw(self, context):
- self.__impl.draw(self, context)
+ def draw(self, _):
+ layout = self.layout
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
+ layout.prop(self, "tgt_density")
+ layout.prop(self, "tgt_texture_size")
+ layout.prop(self, "origin")
+
+ layout.separator()
+
+ def invoke(self, context, _):
+ if self.show_dialog:
+ wm = context.window_manager
+ return wm.invoke_props_dialog(self)
+
+ return self.execute(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ return self.__apply_manual(context)
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
"""
Operation class: Apply scaled UV (Scaling Density)
@@ -227,13 +417,13 @@ class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
bl_description = "Apply scaled UV with scaling density"
bl_options = {'REGISTER', 'UNDO'}
- tgt_scaling_factor: FloatProperty(
+ tgt_scaling_factor = FloatProperty(
name="Scaling Factor",
default=1.0,
max=1000.0,
min=0.00001
)
- origin: EnumProperty(
+ origin = EnumProperty(
name="Origin",
description="Aspect Origin",
items=[
@@ -250,44 +440,97 @@ class MUV_OT_WorldScaleUV_ApplyScalingDensity(bpy.types.Operator):
],
default='CENTER'
)
- src_density: FloatProperty(
+ src_density = FloatProperty(
name="Density",
description="Source Texel Density",
default=0.0,
min=0.0,
options={'HIDDEN'}
)
- same_density: BoolProperty(
+ same_density = BoolProperty(
name="Same Density",
description="Apply same density",
default=False,
options={'HIDDEN'}
)
- show_dialog: BoolProperty(
+ show_dialog = BoolProperty(
name="Show Diaglog Menu",
description="Show dialog menu if true",
default=True,
options={'HIDDEN', 'SKIP_SAVE'}
)
- def __init__(self):
- self.__impl = impl.ApplyScalingDensityImpl()
-
@classmethod
def poll(cls, context):
- return impl.ApplyScalingDensityImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
+
+ def __apply_scaling_density(self, context):
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ uv_area, _, density = _measure_wsuv_info(obj)
+ if not uv_area:
+ self.report({'WARNING'},
+ "Object must have more than one UV map and texture")
+ return {'CANCELLED'}
+
+ tgt_density = self.src_density * self.tgt_scaling_factor
+ factor = tgt_density / density
+
+ _apply(context.active_object, self.origin, factor)
+ self.report({'INFO'}, "Scaling factor: {0}".format(factor))
+
+ return {'FINISHED'}
+
+ def draw(self, _):
+ layout = self.layout
- def draw(self, context):
- self.__impl.draw(self, context)
+ layout.label(text="Source:")
+ col = layout.column()
+ col.prop(self, "src_density")
+ col.enabled = False
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
+ layout.separator()
+
+ if not self.same_density:
+ layout.prop(self, "tgt_scaling_factor")
+ layout.prop(self, "origin")
+
+ layout.separator()
+
+ def invoke(self, context, _):
+ sc = context.scene
+
+ if self.show_dialog:
+ wm = context.window_manager
+
+ if self.same_density:
+ self.tgt_scaling_factor = 1.0
+ else:
+ self.tgt_scaling_factor = \
+ sc.muv_world_scale_uv_tgt_scaling_factor
+ self.src_density = sc.muv_world_scale_uv_src_density
+
+ return wm.invoke_props_dialog(self)
+
+ return self.execute(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ if self.same_density:
+ self.tgt_scaling_factor = 1.0
+
+ return self.__apply_scaling_density(context)
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
"""
Operation class: Apply scaled UV (Proportional to mesh)
@@ -298,7 +541,7 @@ class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
bl_description = "Apply scaled UV proportionaled to mesh"
bl_options = {'REGISTER', 'UNDO'}
- origin: EnumProperty(
+ origin = EnumProperty(
name="Origin",
description="Aspect Origin",
items=[
@@ -315,46 +558,91 @@ class MUV_OT_WorldScaleUV_ApplyProportionalToMesh(bpy.types.Operator):
],
default='CENTER'
)
- src_density: FloatProperty(
+ src_density = FloatProperty(
name="Source Density",
description="Source Texel Density",
default=0.0,
min=0.0,
options={'HIDDEN'}
)
- src_uv_area: FloatProperty(
+ src_uv_area = FloatProperty(
name="Source UV Area",
description="Source UV Area",
default=0.0,
min=0.0,
options={'HIDDEN'}
)
- src_mesh_area: FloatProperty(
+ src_mesh_area = FloatProperty(
name="Source Mesh Area",
description="Source Mesh Area",
default=0.0,
min=0.0,
options={'HIDDEN'}
)
- show_dialog: BoolProperty(
+ show_dialog = BoolProperty(
name="Show Diaglog Menu",
description="Show dialog menu if true",
default=True,
options={'HIDDEN', 'SKIP_SAVE'}
)
- def __init__(self):
- self.__impl = impl.ApplyProportionalToMeshImpl()
-
@classmethod
def poll(cls, context):
- return impl.ApplyProportionalToMeshImpl.poll(context)
+ # we can not get area/space/region from console
+ if common.is_console_mode():
+ return True
+ return _is_valid_context(context)
+
+ def __apply_proportional_to_mesh(self, context):
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ if common.check_version(2, 73, 0) >= 0:
+ bm.verts.ensure_lookup_table()
+ bm.edges.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ uv_area, mesh_area, density = _measure_wsuv_info(obj)
+ if not uv_area:
+ self.report({'WARNING'},
+ "Object must have more than one UV map and texture")
+ return {'CANCELLED'}
+
+ tgt_density = self.src_density * sqrt(mesh_area) / sqrt(
+ self.src_mesh_area)
+
+ factor = tgt_density / density
+
+ _apply(context.active_object, self.origin, factor)
+ self.report({'INFO'}, "Scaling factor: {0}".format(factor))
+
+ return {'FINISHED'}
+
+ def draw(self, _):
+ layout = self.layout
+
+ layout.label(text="Source:")
+ col = layout.column(align=True)
+ col.prop(self, "src_density")
+ col.prop(self, "src_uv_area")
+ col.prop(self, "src_mesh_area")
+ col.enabled = False
+
+ layout.separator()
+ layout.prop(self, "origin")
+
+ layout.separator()
+
+ def invoke(self, context, _):
+ if self.show_dialog:
+ wm = context.window_manager
+ sc = context.scene
+
+ self.src_density = sc.muv_world_scale_uv_src_density
+ self.src_mesh_area = sc.muv_world_scale_uv_src_mesh_area
- def draw(self, context):
- self.__impl.draw(self, context)
+ return wm.invoke_props_dialog(self)
- def invoke(self, context, event):
- return self.__impl.invoke(self, context, event)
+ return self.execute(context)
def execute(self, context):
- return self.__impl.execute(self, context)
+ return self.__apply_proportional_to_mesh(context)
diff --git a/uv_magic_uv/preferences.py b/uv_magic_uv/preferences.py
index a58d08d4..01d7155e 100644
--- a/uv_magic_uv/preferences.py
+++ b/uv_magic_uv/preferences.py
@@ -37,6 +37,7 @@ from . import op
from . import ui
from .utils.bl_class_registry import BlClassRegistry
from .utils.addon_updator import AddonUpdatorManager
+from .utils import compatibility as compat
def view3d_uvmap_menu_fn(self, context):
@@ -44,7 +45,7 @@ def view3d_uvmap_menu_fn(self, context):
sc = context.scene
layout.separator()
- layout.label(text="Copy/Paste UV", icon='IMAGE')
+ layout.label(text="Copy/Paste UV", icon=compat.icon('IMAGE'))
# Copy/Paste UV
layout.menu(ui.VIEW3D_MT_uv_map.MUV_MT_CopyPasteUV.bl_idname,
text="Copy/Paste UV")
@@ -53,7 +54,7 @@ def view3d_uvmap_menu_fn(self, context):
text="Transfer UV")
layout.separator()
- layout.label(text="UV Manipulation", icon='IMAGE')
+ layout.label(text="UV Manipulation", icon=compat.icon('IMAGE'))
# Flip/Rotate UV
ops = layout.operator(op.flip_rotate_uv.MUV_OT_FlipRotate.bl_idname,
text="Flip/Rotate UV")
@@ -80,7 +81,7 @@ def view3d_uvmap_menu_fn(self, context):
layout.prop(sc, "muv_uv_sculpt_enable", text="UV Sculpt")
layout.separator()
- layout.label(text="UV Mapping", icon='IMAGE')
+ layout.label(text="UV Mapping", icon=compat.icon('IMAGE'))
# Unwrap Constraint
ops = layout.operator(
op.unwrap_constraint.MUV_OT_UnwrapConstraint.bl_idname,
@@ -98,7 +99,7 @@ def view3d_object_menu_fn(self, _):
layout = self.layout
layout.separator()
- layout.label(text="Copy/Paste UV", icon='IMAGE')
+ layout.label(text="Copy/Paste UV", icon=compat.icon('IMAGE'))
# Copy/Paste UV (Among Object)
layout.menu(ui.VIEW3D_MT_object.MUV_MT_CopyPasteUV_Object.bl_idname,
text="Copy/Paste UV")
@@ -110,13 +111,13 @@ def image_uvs_menu_fn(self, context):
layout.separator()
# Copy/Paste UV (on UV/Image Editor)
- layout.label(text="Copy/Paste UV", icon='IMAGE')
+ layout.label(text="Copy/Paste UV", icon=compat.icon('IMAGE'))
layout.menu(ui.IMAGE_MT_uvs.MUV_MT_CopyPasteUV_UVEdit.bl_idname,
text="Copy/Paste UV")
layout.separator()
# Pack UV
- layout.label(text="UV Manipulation", icon='IMAGE')
+ layout.label(text="UV Manipulation", icon=compat.icon('IMAGE'))
ops = layout.operator(op.pack_uv.MUV_OT_PackUV.bl_idname, text="Pack UV")
ops.allowable_center_deviation = sc.muv_pack_uv_allowable_center_deviation
ops.allowable_size_deviation = sc.muv_pack_uv_allowable_size_deviation
@@ -133,7 +134,7 @@ def image_uvs_menu_fn(self, context):
layout.separator()
# Align UV Cursor
- layout.label(text="Editor Enhancement", icon='IMAGE')
+ layout.label(text="Editor Enhancement", icon=compat.icon('IMAGE'))
layout.menu(ui.IMAGE_MT_uvs.MUV_MT_AlignUVCursor.bl_idname,
text="Align UV Cursor")
# UV Bounding Box
@@ -170,13 +171,14 @@ class MUV_OT_CheckAddonUpdate(bpy.types.Operator):
@BlClassRegistry()
+@compat.make_annotations
class MUV_OT_UpdateAddon(bpy.types.Operator):
bl_idname = "uv.muv_update_addon"
bl_label = "Update"
bl_description = "Update Add-on"
bl_options = {'REGISTER', 'UNDO'}
- branch_name: StringProperty(
+ branch_name = StringProperty(
name="Branch Name",
description="Branch name to update",
default="",
@@ -198,6 +200,7 @@ def get_update_candidate_branches(_, __):
@BlClassRegistry()
+@compat.make_annotations
class Preferences(AddonPreferences):
"""Preferences class: Preferences for this add-on"""
@@ -210,7 +213,7 @@ class Preferences(AddonPreferences):
remove_builtin_menu()
# enable to add features to built-in menu
- enable_builtin_menu: BoolProperty(
+ enable_builtin_menu = BoolProperty(
name="Built-in Menu",
description="Enable built-in menu",
default=True,
@@ -218,7 +221,7 @@ class Preferences(AddonPreferences):
)
# for UV Sculpt
- uv_sculpt_brush_color: FloatVectorProperty(
+ uv_sculpt_brush_color = FloatVectorProperty(
name="Color",
description="Color",
default=(1.0, 0.4, 0.4, 1.0),
@@ -229,7 +232,7 @@ class Preferences(AddonPreferences):
)
# for Overlapped UV
- uv_inspection_overlapped_color: FloatVectorProperty(
+ uv_inspection_overlapped_color = FloatVectorProperty(
name="Color",
description="Color",
default=(0.0, 0.0, 1.0, 0.3),
@@ -240,7 +243,7 @@ class Preferences(AddonPreferences):
)
# for Flipped UV
- uv_inspection_flipped_color: FloatVectorProperty(
+ uv_inspection_flipped_color = FloatVectorProperty(
name="Color",
description="Color",
default=(1.0, 0.0, 0.0, 0.3),
@@ -251,7 +254,7 @@ class Preferences(AddonPreferences):
)
# for Texture Projection
- texture_projection_canvas_padding: FloatVectorProperty(
+ texture_projection_canvas_padding = FloatVectorProperty(
name="Canvas Padding",
description="Canvas Padding",
size=2,
@@ -260,13 +263,13 @@ class Preferences(AddonPreferences):
default=(20.0, 20.0))
# for UV Bounding Box
- uv_bounding_box_cp_size: FloatProperty(
+ uv_bounding_box_cp_size = FloatProperty(
name="Size",
description="Control Point Size",
default=6.0,
min=3.0,
max=100.0)
- uv_bounding_box_cp_react_size: FloatProperty(
+ uv_bounding_box_cp_react_size = FloatProperty(
name="React Size",
description="Size event fired",
default=10.0,
@@ -274,7 +277,7 @@ class Preferences(AddonPreferences):
max=100.0)
# for UI
- category: EnumProperty(
+ category = EnumProperty(
name="Category",
description="Preferences Category",
items=[
@@ -284,39 +287,39 @@ class Preferences(AddonPreferences):
],
default='INFO'
)
- info_desc_expanded: BoolProperty(
+ info_desc_expanded = BoolProperty(
name="Description",
description="Description",
default=False
)
- info_loc_expanded: BoolProperty(
+ info_loc_expanded = BoolProperty(
name="Location",
description="Location",
default=False
)
- conf_uv_sculpt_expanded: BoolProperty(
+ conf_uv_sculpt_expanded = BoolProperty(
name="UV Sculpt",
description="UV Sculpt",
default=False
)
- conf_uv_inspection_expanded: BoolProperty(
+ conf_uv_inspection_expanded = BoolProperty(
name="UV Inspection",
description="UV Inspection",
default=False
)
- conf_texture_projection_expanded: BoolProperty(
+ conf_texture_projection_expanded = BoolProperty(
name="Texture Projection",
description="Texture Projection",
default=False
)
- conf_uv_bounding_box_expanded: BoolProperty(
+ conf_uv_bounding_box_expanded = BoolProperty(
name="UV Bounding Box",
description="UV Bounding Box",
default=False
)
# for add-on updater
- updater_branch_to_update: EnumProperty(
+ updater_branch_to_update = EnumProperty(
name="branch",
description="Target branch to update add-on",
items=get_update_candidate_branches
@@ -349,27 +352,27 @@ class Preferences(AddonPreferences):
else 'DISCLOSURE_TRI_RIGHT')
if self.info_loc_expanded:
row = layout.row(align=True)
- sp = row.split(factor=0.5)
+ sp = compat.layout_split(row, 0.5)
sp.label(text="3D View > Tool shelf > " +
"Copy/Paste UV (Object mode)")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="Copy/Paste UV (Among objects)")
row = layout.row(align=True)
- sp = row.split(factor=0.5)
+ sp = compat.layout_split(row, 0.5)
sp.label(text="3D View > Tool shelf > " +
"Copy/Paste UV (Edit mode)")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="Copy/Paste UV (Among faces in 3D View)")
col.label(text="Transfer UV")
row = layout.row(align=True)
- sp = row.split(factor=0.5)
+ sp = compat.layout_split(row, 0.5)
sp.label(text="3D View > Tool shelf > " +
"UV Manipulation (Edit mode)")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="Flip/Rotate UV")
col.label(text="Mirror UV")
@@ -381,26 +384,26 @@ class Preferences(AddonPreferences):
col.label(text="UV Sculpt")
row = layout.row(align=True)
- sp = row.split(factor=0.5)
+ sp = compat.layout_split(row, 0.5)
sp.label(text="3D View > Tool shelf > " +
"UV Manipulation (Edit mode)")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="Unwrap Constraint")
col.label(text="Texture Projection")
col.label(text="UVW")
row = layout.row(align=True)
- sp = row.split(factor=0.5)
+ sp = compat.layout_split(row, 0.5)
sp.label(text="UV/Image Editor > Tool shelf > Copy/Paste UV")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="Copy/Paste UV (Among faces in UV/Image Editor)")
row = layout.row(align=True)
- sp = row.split(factor=0.5)
+ sp = compat.layout_split(row, 0.5)
sp.label(text="UV/Image Editor > Tool shelf > UV Manipulation")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="Align UV")
col.label(text="Smooth UV")
@@ -408,10 +411,10 @@ class Preferences(AddonPreferences):
col.label(text="Pack UV (Extension)")
row = layout.row(align=True)
- sp = row.split(factor=0.5)
+ sp = compat.layout_split(row, 0.5)
sp.label(text="UV/Image Editor > Tool shelf > " +
"Editor Enhancement")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="Align UV Cursor")
col.label(text="UV Cursor Location")
@@ -430,9 +433,9 @@ class Preferences(AddonPreferences):
icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_sculpt_expanded
else 'DISCLOSURE_TRI_RIGHT')
if self.conf_uv_sculpt_expanded:
- sp = layout.split(factor=0.05)
+ sp = compat.layout_split(layout, 0.05)
col = sp.column() # spacer
- sp = sp.split(factor=0.3)
+ sp = compat.layout_split(sp, 0.3)
col = sp.column()
col.label(text="Brush Color:")
col.prop(self, "uv_sculpt_brush_color", text="")
@@ -443,13 +446,13 @@ class Preferences(AddonPreferences):
icon='DISCLOSURE_TRI_DOWN' if self.conf_uv_inspection_expanded
else 'DISCLOSURE_TRI_RIGHT')
if self.conf_uv_inspection_expanded:
- sp = layout.split(factor=0.05)
+ sp = compat.layout_split(layout, 0.05)
col = sp.column() # spacer
- sp = sp.split(factor=0.3)
+ sp = compat.layout_split(sp, 0.3)
col = sp.column()
col.label(text="Overlapped UV Color:")
col.prop(self, "uv_inspection_overlapped_color", text="")
- sp = sp.split(factor=0.45)
+ sp = compat.layout_split(sp, 0.45)
col = sp.column()
col.label(text="Flipped UV Color:")
col.prop(self, "uv_inspection_flipped_color", text="")
@@ -462,9 +465,9 @@ class Preferences(AddonPreferences):
if self.conf_texture_projection_expanded
else 'DISCLOSURE_TRI_RIGHT')
if self.conf_texture_projection_expanded:
- sp = layout.split(factor=0.05)
+ sp = compat.layout_split(layout, 0.05)
col = sp.column() # spacer
- sp = sp.split(factor=0.3)
+ sp = compat.layout_split(sp, 0.3)
col = sp.column()
col.prop(self, "texture_projection_canvas_padding")
layout.separator()
@@ -475,9 +478,9 @@ class Preferences(AddonPreferences):
if self.conf_uv_bounding_box_expanded
else 'DISCLOSURE_TRI_RIGHT')
if self.conf_uv_bounding_box_expanded:
- sp = layout.split(factor=0.05)
+ sp = compat.layout_split(layout, 0.05)
col = sp.column() # spacer
- sp = sp.split(factor=0.3)
+ sp = compat.layout_split(sp, 0.3)
col = sp.column()
col.label(text="Control Point:")
col.prop(self, "uv_bounding_box_cp_size")
diff --git a/uv_magic_uv/properites.py b/uv_magic_uv/properites.py
index 60ce26eb..81ebbb4d 100644
--- a/uv_magic_uv/properites.py
+++ b/uv_magic_uv/properites.py
@@ -24,16 +24,6 @@ __version__ = "5.2"
__date__ = "17 Nov 2018"
-from .utils.property_class_registry import PropertyClassRegistry
-
-
-__all__ = [
- 'MUV_Properties',
- 'init_props',
- 'clear_props',
-]
-
-
# Properties used in this add-on.
# pylint: disable=W0612
class MUV_Properties():
@@ -41,6 +31,7 @@ class MUV_Properties():
self.prefs = MUV_Prefs()
+# TODO: delete this
class MUV_Prefs():
expanded = {
"info_desc": False,
diff --git a/uv_magic_uv/ui/IMAGE_MT_uvs.py b/uv_magic_uv/ui/IMAGE_MT_uvs.py
index dfb509c7..3881f547 100644
--- a/uv_magic_uv/ui/IMAGE_MT_uvs.py
+++ b/uv_magic_uv/ui/IMAGE_MT_uvs.py
@@ -41,10 +41,6 @@ from ..op.select_uv import (
from ..op.uv_inspection import MUV_OT_UVInspection_Update
from ..utils.bl_class_registry import BlClassRegistry
-__all__ = [
- 'MUV_MT_CopyPasteUV_UVEdit',
-]
-
@BlClassRegistry()
class MUV_MT_CopyPasteUV_UVEdit(bpy.types.Menu):
diff --git a/uv_magic_uv/ui/VIEW3D_MT_object.py b/uv_magic_uv/ui/VIEW3D_MT_object.py
index 318cd82c..0d51a65b 100644
--- a/uv_magic_uv/ui/VIEW3D_MT_object.py
+++ b/uv_magic_uv/ui/VIEW3D_MT_object.py
@@ -28,10 +28,6 @@ import bpy
from ..op import copy_paste_uv_object
from ..utils.bl_class_registry import BlClassRegistry
-__all__ = [
- 'MUV_MT_CopyPasteUV_Object',
-]
-
@BlClassRegistry()
class MUV_MT_CopyPasteUV_Object(bpy.types.Menu):
diff --git a/uv_magic_uv/ui/VIEW3D_MT_uv_map.py b/uv_magic_uv/ui/VIEW3D_MT_uv_map.py
index 012ce047..d673ed4d 100644
--- a/uv_magic_uv/ui/VIEW3D_MT_uv_map.py
+++ b/uv_magic_uv/ui/VIEW3D_MT_uv_map.py
@@ -45,18 +45,9 @@ from ..op.world_scale_uv import (
MUV_OT_WorldScaleUV_ApplyScalingDensity,
MUV_OT_WorldScaleUV_ApplyProportionalToMesh,
)
-from ..op.texture_projection import (
- MUV_OT_TextureProjection,
- MUV_OT_TextureProjection_Project,
-)
+from ..op.texture_projection import MUV_OT_TextureProjection_Project
from ..utils.bl_class_registry import BlClassRegistry
-__all__ = [
- 'MUV_MT_CopyPasteUV',
- 'MUV_MT_TransferUV',
- 'MUV_MT_UVW',
-]
-
@BlClassRegistry()
class MUV_MT_CopyPasteUV(bpy.types.Menu):
diff --git a/uv_magic_uv/ui/uvedit_copy_paste_uv.py b/uv_magic_uv/ui/uvedit_copy_paste_uv.py
index e21a5abd..7b8a1c52 100644
--- a/uv_magic_uv/ui/uvedit_copy_paste_uv.py
+++ b/uv_magic_uv/ui/uvedit_copy_paste_uv.py
@@ -27,13 +27,11 @@ import bpy
from ..op import copy_paste_uv_uvedit
from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_UVEdit_CopyPasteUV',
-]
+from ..utils import compatibility as compat
@BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
class MUV_PT_UVEdit_CopyPasteUV(bpy.types.Panel):
"""
Panel class: Copy/Paste UV on Property Panel on UV/ImageEditor
@@ -48,7 +46,7 @@ class MUV_PT_UVEdit_CopyPasteUV(bpy.types.Panel):
def draw_header(self, _):
layout = self.layout
- layout.label(text="", icon='IMAGE')
+ layout.label(text="", icon=compat.icon('IMAGE'))
def draw(self, _):
layout = self.layout
diff --git a/uv_magic_uv/ui/uvedit_editor_enhancement.py b/uv_magic_uv/ui/uvedit_editor_enhancement.py
index cfd9ef28..7c366aa7 100644
--- a/uv_magic_uv/ui/uvedit_editor_enhancement.py
+++ b/uv_magic_uv/ui/uvedit_editor_enhancement.py
@@ -34,13 +34,11 @@ from ..op.uv_inspection import (
MUV_OT_UVInspection_Update,
)
from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_UVEdit_EditorEnhancement',
-]
+from ..utils import compatibility as compat
@BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
class MUV_PT_UVEdit_EditorEnhancement(bpy.types.Panel):
"""
Panel class: UV/Image Editor Enhancement
@@ -55,7 +53,7 @@ class MUV_PT_UVEdit_EditorEnhancement(bpy.types.Panel):
def draw_header(self, _):
layout = self.layout
- layout.label(text="", icon='IMAGE')
+ layout.label(text="", icon=compat.icon('IMAGE'))
def draw(self, context):
layout = self.layout
diff --git a/uv_magic_uv/ui/uvedit_uv_manipulation.py b/uv_magic_uv/ui/uvedit_uv_manipulation.py
index f5bd27e3..d8c77957 100644
--- a/uv_magic_uv/ui/uvedit_uv_manipulation.py
+++ b/uv_magic_uv/ui/uvedit_uv_manipulation.py
@@ -39,9 +39,11 @@ from ..op.select_uv import (
)
from ..op.pack_uv import MUV_OT_PackUV
from ..utils.bl_class_registry import BlClassRegistry
+from ..utils import compatibility as compat
@BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
class MUV_PT_UVEdit_UVManipulation(bpy.types.Panel):
"""
Panel class: UV Manipulation on Property Panel on UV/ImageEditor
@@ -56,7 +58,7 @@ class MUV_PT_UVEdit_UVManipulation(bpy.types.Panel):
def draw_header(self, _):
layout = self.layout
- layout.label(text="", icon='IMAGE')
+ layout.label(text="", icon=compat.icon('IMAGE'))
def draw(self, context):
sc = context.scene
diff --git a/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py b/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
index 14fba24a..0fc4df14 100644
--- a/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
+++ b/uv_magic_uv/ui/view3d_copy_paste_uv_editmode.py
@@ -30,13 +30,11 @@ from ..op import (
transfer_uv,
)
from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_CopyPasteUVEditMode',
-]
+from ..utils import compatibility as compat
@BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
class MUV_PT_CopyPasteUVEditMode(bpy.types.Panel):
"""
Panel class: Copy/Paste UV on Property Panel on View3D
@@ -51,7 +49,7 @@ class MUV_PT_CopyPasteUVEditMode(bpy.types.Panel):
def draw_header(self, _):
layout = self.layout
- layout.label(text="", icon='IMAGE')
+ layout.label(text="", icon=compat.icon('IMAGE'))
def draw(self, context):
sc = context.scene
diff --git a/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py b/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
index 6dd0d3b4..36968ffb 100644
--- a/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
+++ b/uv_magic_uv/ui/view3d_copy_paste_uv_objectmode.py
@@ -27,13 +27,11 @@ import bpy
from ..op import copy_paste_uv_object
from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_View3D_Object_CopyPasteUV',
-]
+from ..utils import compatibility as compat
@BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
class MUV_PT_View3D_Object_CopyPasteUV(bpy.types.Panel):
"""
Panel class: Copy/Paste UV on Property Panel on View3D
@@ -48,7 +46,7 @@ class MUV_PT_View3D_Object_CopyPasteUV(bpy.types.Panel):
def draw_header(self, _):
layout = self.layout
- layout.label(text="", icon='IMAGE')
+ layout.label(text="", icon=compat.icon('IMAGE'))
def draw(self, context):
sc = context.scene
diff --git a/uv_magic_uv/ui/view3d_uv_manipulation.py b/uv_magic_uv/ui/view3d_uv_manipulation.py
index 4c09bdf2..e385da38 100644
--- a/uv_magic_uv/ui/view3d_uv_manipulation.py
+++ b/uv_magic_uv/ui/view3d_uv_manipulation.py
@@ -48,13 +48,11 @@ from ..op.mirror_uv import MUV_OT_MirrorUV
from ..op.move_uv import MUV_OT_MoveUV
from ..op.preserve_uv_aspect import MUV_OT_PreserveUVAspect
from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_View3D_UVManipulation',
-]
+from ..utils import compatibility as compat
@BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
"""
Panel class: UV Manipulation on Property Panel on View3D
@@ -69,7 +67,7 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
def draw_header(self, _):
layout = self.layout
- layout.label(text="", icon='IMAGE')
+ layout.label(text="", icon=compat.icon('IMAGE'))
def draw(self, context):
sc = context.scene
@@ -108,11 +106,11 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
box.prop(sc, "muv_world_scale_uv_mode", text="")
if sc.muv_world_scale_uv_mode == 'MANUAL':
- sp = box.split(factor=0.5)
+ sp = compat.layout_split(box, 0.5)
col = sp.column()
col.prop(sc, "muv_world_scale_uv_tgt_texture_size",
text="Texture Size")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column()
col.label(text="Density:")
col.prop(sc, "muv_world_scale_uv_tgt_density", text="")
@@ -125,19 +123,19 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
ops.show_dialog = False
elif sc.muv_world_scale_uv_mode == 'SAME_DENSITY':
- sp = box.split(factor=0.4)
+ sp = compat.layout_split(box, 0.4)
col = sp.column(align=True)
col.label(text="Source:")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.operator(MUV_OT_WorldScaleUV_Measure.bl_idname,
text="Measure")
- sp = box.split(factor=0.7)
+ sp = compat.layout_split(box, 0.7)
col = sp.column(align=True)
col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
col.enabled = False
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="px2/cm2")
@@ -152,19 +150,19 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
ops.show_dialog = False
elif sc.muv_world_scale_uv_mode == 'SCALING_DENSITY':
- sp = box.split(factor=0.4)
+ sp = compat.layout_split(box, 0.4)
col = sp.column(align=True)
col.label(text="Source:")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.operator(MUV_OT_WorldScaleUV_Measure.bl_idname,
text="Measure")
- sp = box.split(factor=0.7)
+ sp = compat.layout_split(box, 0.7)
col = sp.column(align=True)
col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
col.enabled = False
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="px2/cm2")
@@ -183,22 +181,22 @@ class MUV_PT_View3D_UVManipulation(bpy.types.Panel):
sc.muv_world_scale_uv_tgt_scaling_factor
elif sc.muv_world_scale_uv_mode == 'PROPORTIONAL_TO_MESH':
- sp = box.split(factor=0.4)
+ sp = compat.layout_split(box, 0.4)
col = sp.column(align=True)
col.label(text="Source:")
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.operator(MUV_OT_WorldScaleUV_Measure.bl_idname,
text="Measure")
- sp = box.split(factor=0.7)
+ sp = compat.layout_split(box, 0.7)
col = sp.column(align=True)
col.prop(sc, "muv_world_scale_uv_src_mesh_area",
text="Mesh Area")
col.prop(sc, "muv_world_scale_uv_src_uv_area", text="UV Area")
col.prop(sc, "muv_world_scale_uv_src_density", text="Density")
col.enabled = False
- sp = sp.split(factor=1.0)
+ sp = compat.layout_split(sp, 1.0)
col = sp.column(align=True)
col.label(text="cm2")
col.label(text="px2")
diff --git a/uv_magic_uv/ui/view3d_uv_mapping.py b/uv_magic_uv/ui/view3d_uv_mapping.py
index e64a2ce1..9a75de49 100644
--- a/uv_magic_uv/ui/view3d_uv_mapping.py
+++ b/uv_magic_uv/ui/view3d_uv_mapping.py
@@ -34,13 +34,11 @@ from ..op.texture_projection import (
)
from ..op.unwrap_constraint import MUV_OT_UnwrapConstraint
from ..utils.bl_class_registry import BlClassRegistry
-
-__all__ = [
- 'MUV_PT_View3D_UVMapping',
-]
+from ..utils import compatibility as compat
@BlClassRegistry()
+@compat.ChangeRegionType(region_type='TOOLS')
class MUV_PT_View3D_UVMapping(bpy.types.Panel):
"""
Panel class: UV Mapping on Property Panel on View3D
@@ -55,7 +53,7 @@ class MUV_PT_View3D_UVMapping(bpy.types.Panel):
def draw_header(self, _):
layout = self.layout
- layout.label(text="", icon='IMAGE')
+ layout.label(text="", icon=compat.icon('IMAGE'))
def draw(self, context):
sc = context.scene
diff --git a/uv_magic_uv/utils/__init__.py b/uv_magic_uv/utils/__init__.py
index 333a3873..01b1fc00 100644
--- a/uv_magic_uv/utils/__init__.py
+++ b/uv_magic_uv/utils/__init__.py
@@ -27,10 +27,12 @@ if "bpy" in locals():
import importlib
importlib.reload(addon_updator)
importlib.reload(bl_class_registry)
+ importlib.reload(compatibility)
importlib.reload(property_class_registry)
else:
from . import addon_updator
from . import bl_class_registry
+ from . import compatibility
from . import property_class_registry
import bpy
diff --git a/uv_magic_uv/utils/bl_class_registry.py b/uv_magic_uv/utils/bl_class_registry.py
index d1730615..408e6fd6 100644
--- a/uv_magic_uv/utils/bl_class_registry.py
+++ b/uv_magic_uv/utils/bl_class_registry.py
@@ -27,10 +27,6 @@ import bpy
from .. import common
-__all__ = [
- 'BlClassRegistry',
-]
-
class BlClassRegistry:
class_list = []
diff --git a/uv_magic_uv/utils/compatibility.py b/uv_magic_uv/utils/compatibility.py
new file mode 100644
index 00000000..2ccd463c
--- /dev/null
+++ b/uv_magic_uv/utils/compatibility.py
@@ -0,0 +1,189 @@
+# <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__ = "Nutti <nutti.metro@gmail.com>"
+__status__ = "production"
+__version__ = "5.2"
+__date__ = "17 Nov 2018"
+
+import bpy
+import bgl
+import blf
+
+
+def check_version(major, minor, _):
+ """
+ Check blender version
+ """
+
+ if bpy.app.version[0] == major and bpy.app.version[1] == minor:
+ return 0
+ if bpy.app.version[0] > major:
+ return 1
+ if bpy.app.version[1] > minor:
+ return 1
+ return -1
+
+
+def make_annotations(cls):
+ if check_version(2, 80, 0) < 0:
+ return cls
+
+ # make annotation from attributes
+ props = {k: v for k, v in cls.__dict__.items() if isinstance(v, tuple)}
+ if props:
+ if '__annotations__' not in cls.__dict__:
+ setattr(cls, '__annotations__', {})
+ annotations = cls.__dict__['__annotations__']
+ for k, v in props.items():
+ annotations[k] = v
+ delattr(cls, k)
+
+ return cls
+
+
+class ChangeRegionType:
+ def __init__(self, *_, **kwargs):
+ self.region_type = kwargs.get('region_type', False)
+
+ def __call__(self, cls):
+ if check_version(2, 80, 0) >= 0:
+ return cls
+
+ cls.bl_region_type = self.region_type
+
+ return cls
+
+
+def matmul(m1, m2):
+ if check_version(2, 80, 0) < 0:
+ return m1 * m2
+
+ return m1 @ m2
+
+
+def layout_split(layout, factor=0.0, align=False):
+ if check_version(2, 80, 0) < 0:
+ return layout.split(percentage=factor, align=align)
+
+ return layout.split(factor=factor, align=align)
+
+
+def get_user_preferences(context):
+ if hasattr(context, "user_preferences"):
+ return context.user_preferences
+
+ return context.preferences
+
+
+def get_object_select(obj):
+ if check_version(2, 80, 0) < 0:
+ return obj.select
+
+ return obj.select_get()
+
+
+def set_active_object(obj):
+ if check_version(2, 80, 0) < 0:
+ bpy.context.scene.objects.active = obj
+ else:
+ bpy.context.view_layer.objects.active = obj
+
+
+def get_active_object(context):
+ if check_version(2, 80, 0) >= 0:
+ return context.scene.active_object
+ else:
+ return context.active_object
+
+
+def object_has_uv_layers(obj):
+ if check_version(2, 80, 0) < 0:
+ return hasattr(obj.data, "uv_textures")
+ else:
+ return hasattr(obj.data, "uv_layers")
+
+
+def get_object_uv_layers(obj):
+ if check_version(2, 80, 0) < 0:
+ return obj.data.uv_textures
+ else:
+ return obj.data.uv_layers
+
+
+def icon(icon):
+ if icon == 'IMAGE':
+ if check_version(2, 80, 0) < 0:
+ return 'IMAGE_COL'
+
+ return icon
+
+
+def set_blf_font_color(font_id, r, g, b, a):
+ if check_version(2, 80, 0) >= 0:
+ blf.color(font_id, r, g, b, a)
+ else:
+ bgl.glColor4f(r, g, b, a)
+
+
+def set_blf_blur(font_id, radius):
+ if check_version(2, 80, 0) < 0:
+ blf.blur(font_id, radius)
+
+
+def get_all_space_types():
+ if check_version(2, 80, 0) >= 0:
+ return {
+ 'CLIP_EDITOR': bpy.types.SpaceClipEditor,
+ 'CONSOLE': bpy.types.SpaceConsole,
+ 'DOPESHEET_EDITOR': bpy.types.SpaceDopeSheetEditor,
+ 'FILE_BROWSER': bpy.types.SpaceFileBrowser,
+ 'GRAPH_EDITOR': bpy.types.SpaceGraphEditor,
+ 'IMAGE_EDITOR': bpy.types.SpaceImageEditor,
+ 'INFO': bpy.types.SpaceInfo,
+ 'NLA_EDITOR': bpy.types.SpaceNLA,
+ 'NODE_EDITOR': bpy.types.SpaceNodeEditor,
+ 'OUTLINER': bpy.types.SpaceOutliner,
+ 'PROPERTIES': bpy.types.SpaceProperties,
+ 'SEQUENCE_EDITOR': bpy.types.SpaceSequenceEditor,
+ 'TEXT_EDITOR': bpy.types.SpaceTextEditor,
+ 'USER_PREFERENCES': bpy.types.SpacePreferences,
+ 'VIEW_3D': bpy.types.SpaceView3D,
+ }
+ else:
+ return {
+ 'VIEW_3D': bpy.types.SpaceView3D,
+ 'TIMELINE': bpy.types.SpaceTimeline,
+ 'GRAPH_EDITOR': bpy.types.SpaceGraphEditor,
+ 'DOPESHEET_EDITOR': bpy.types.SpaceDopeSheetEditor,
+ 'NLA_EDITOR': bpy.types.SpaceNLA,
+ 'IMAGE_EDITOR': bpy.types.SpaceImageEditor,
+ 'SEQUENCE_EDITOR': bpy.types.SpaceSequenceEditor,
+ 'CLIP_EDITOR': bpy.types.SpaceClipEditor,
+ 'TEXT_EDITOR': bpy.types.SpaceTextEditor,
+ 'NODE_EDITOR': bpy.types.SpaceNodeEditor,
+ 'LOGIC_EDITOR': bpy.types.SpaceLogicEditor,
+ 'PROPERTIES': bpy.types.SpaceProperties,
+ 'OUTLINER': bpy.types.SpaceOutliner,
+ 'USER_PREFERENCES': bpy.types.SpaceUserPreferences,
+ 'INFO': bpy.types.SpaceInfo,
+ 'FILE_BROWSER': bpy.types.SpaceFileBrowser,
+ 'CONSOLE': bpy.types.SpaceConsole,
+ }
diff --git a/uv_magic_uv/utils/property_class_registry.py b/uv_magic_uv/utils/property_class_registry.py
index 20df0342..4e89da54 100644
--- a/uv_magic_uv/utils/property_class_registry.py
+++ b/uv_magic_uv/utils/property_class_registry.py
@@ -25,10 +25,6 @@ __date__ = "17 Nov 2018"
from .. import common
-__all__ = [
- 'PropertyClassRegistry',
-]
-
class PropertyClassRegistry:
class_list = []