Update for 2.8
[blender-addons.git] / uv_magic_uv / op / copy_paste_uv_object.py
blobd80ee4152a4ffc133c9b6eeb801968eb28b230ca
1 # <pep8-80 compliant>
3 # ##### BEGIN GPL LICENSE BLOCK #####
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # ##### END GPL LICENSE BLOCK #####
21 __author__ = "Nutti <nutti.metro@gmail.com>"
22 __status__ = "production"
23 __version__ = "5.1"
24 __date__ = "24 Feb 2018"
26 import bpy
27 import bmesh
28 from bpy.props import (
29 StringProperty,
30 BoolProperty,
33 from .. import common
36 def memorize_view_3d_mode(fn):
37 def __memorize_view_3d_mode(self, context):
38 mode_orig = bpy.context.object.mode
39 result = fn(self, context)
40 bpy.ops.object.mode_set(mode=mode_orig)
41 return result
42 return __memorize_view_3d_mode
45 class MUV_CPUVObjCopyUV(bpy.types.Operator):
46 """
47 Operation class: Copy UV coordinate per object
48 """
50 bl_idname = "object.muv_cpuv_obj_copy_uv"
51 bl_label = "Copy UV"
52 bl_description = "Copy UV coordinate"
53 bl_options = {'REGISTER', 'UNDO'}
55 uv_map = StringProperty(options={'HIDDEN'})
57 @memorize_view_3d_mode
58 def execute(self, context):
59 props = context.scene.muv_props.cpuv_obj
60 if self.uv_map == "":
61 self.report({'INFO'}, "Copy UV coordinate per object")
62 else:
63 self.report(
64 {'INFO'},
65 "Copy UV coordinate per object (UV map:%s)" % (self.uv_map))
66 bpy.ops.object.mode_set(mode='EDIT')
68 obj = context.active_object
69 bm = bmesh.from_edit_mesh(obj.data)
70 if common.check_version(2, 73, 0) >= 0:
71 bm.faces.ensure_lookup_table()
73 # get UV layer
74 if self.uv_map == "":
75 if not bm.loops.layers.uv:
76 self.report(
77 {'WARNING'}, "Object must have more than one UV map")
78 return {'CANCELLED'}
79 uv_layer = bm.loops.layers.uv.verify()
80 else:
81 uv_layer = bm.loops.layers.uv[self.uv_map]
83 # get selected face
84 props.src_uvs = []
85 props.src_pin_uvs = []
86 props.src_seams = []
87 for face in bm.faces:
88 uvs = [l[uv_layer].uv.copy() for l in face.loops]
89 pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
90 seams = [l.edge.seam for l in face.loops]
91 props.src_uvs.append(uvs)
92 props.src_pin_uvs.append(pin_uvs)
93 props.src_seams.append(seams)
95 self.report({'INFO'}, "%s's UV coordinates are copied" % (obj.name))
97 return {'FINISHED'}
100 class MUV_CPUVObjCopyUVMenu(bpy.types.Menu):
102 Menu class: Copy UV coordinate per object
105 bl_idname = "object.muv_cpuv_obj_copy_uv_menu"
106 bl_label = "Copy UV"
107 bl_description = "Copy UV coordinate per object"
109 def draw(self, _):
110 layout = self.layout
111 # create sub menu
112 uv_maps = bpy.context.active_object.data.uv_textures.keys()
113 layout.operator(MUV_CPUVObjCopyUV.bl_idname, text="[Default]")\
114 .uv_map = ""
115 for m in uv_maps:
116 layout.operator(MUV_CPUVObjCopyUV.bl_idname, text=m).uv_map = m
119 class MUV_CPUVObjPasteUV(bpy.types.Operator):
121 Operation class: Paste UV coordinate per object
124 bl_idname = "object.muv_cpuv_obj_paste_uv"
125 bl_label = "Paste UV"
126 bl_description = "Paste UV coordinate"
127 bl_options = {'REGISTER', 'UNDO'}
129 uv_map = StringProperty(options={'HIDDEN'})
130 copy_seams = BoolProperty(
131 name="Copy Seams",
132 description="Copy Seams",
133 default=True
136 @memorize_view_3d_mode
137 def execute(self, context):
138 props = context.scene.muv_props.cpuv_obj
139 if not props.src_uvs or not props.src_pin_uvs:
140 self.report({'WARNING'}, "Need copy UV at first")
141 return {'CANCELLED'}
143 for o in bpy.data.objects:
144 if not hasattr(o.data, "uv_textures") or not o.select:
145 continue
147 bpy.ops.object.mode_set(mode='OBJECT')
148 bpy.context.scene.objects.active = o
149 bpy.ops.object.mode_set(mode='EDIT')
151 obj = context.active_object
152 bm = bmesh.from_edit_mesh(obj.data)
153 if common.check_version(2, 73, 0) >= 0:
154 bm.faces.ensure_lookup_table()
156 if (self.uv_map == "" or
157 self.uv_map not in bm.loops.layers.uv.keys()):
158 self.report({'INFO'}, "Paste UV coordinate per object")
159 else:
160 self.report(
161 {'INFO'},
162 "Paste UV coordinate per object (UV map: %s)"
163 % (self.uv_map))
165 # get UV layer
166 if (self.uv_map == "" or
167 self.uv_map not in bm.loops.layers.uv.keys()):
168 if not bm.loops.layers.uv:
169 self.report(
170 {'WARNING'}, "Object must have more than one UV map")
171 return {'CANCELLED'}
172 uv_layer = bm.loops.layers.uv.verify()
173 else:
174 uv_layer = bm.loops.layers.uv[self.uv_map]
176 # get selected face
177 dest_uvs = []
178 dest_pin_uvs = []
179 dest_seams = []
180 dest_face_indices = []
181 for face in bm.faces:
182 dest_face_indices.append(face.index)
183 uvs = [l[uv_layer].uv.copy() for l in face.loops]
184 pin_uvs = [l[uv_layer].pin_uv for l in face.loops]
185 seams = [l.edge.seam for l in face.loops]
186 dest_uvs.append(uvs)
187 dest_pin_uvs.append(pin_uvs)
188 dest_seams.append(seams)
189 if len(props.src_uvs) != len(dest_uvs):
190 self.report(
191 {'WARNING'},
192 "Number of faces is different from copied " +
193 "(src:%d, dest:%d)"
194 % (len(props.src_uvs), len(dest_uvs))
196 return {'CANCELLED'}
198 # paste
199 for i, idx in enumerate(dest_face_indices):
200 suv = props.src_uvs[i]
201 spuv = props.src_pin_uvs[i]
202 ss = props.src_seams[i]
203 duv = dest_uvs[i]
204 if len(suv) != len(duv):
205 self.report({'WARNING'}, "Some faces are different size")
206 return {'CANCELLED'}
207 suvs_fr = [uv for uv in suv]
208 spuvs_fr = [pin_uv for pin_uv in spuv]
209 ss_fr = [s for s in ss]
210 # paste UVs
211 for l, suv, spuv, ss in zip(
212 bm.faces[idx].loops, suvs_fr, spuvs_fr, ss_fr):
213 l[uv_layer].uv = suv
214 l[uv_layer].pin_uv = spuv
215 if self.copy_seams is True:
216 l.edge.seam = ss
218 bmesh.update_edit_mesh(obj.data)
219 if self.copy_seams is True:
220 obj.data.show_edge_seams = True
222 self.report(
223 {'INFO'}, "%s's UV coordinates are pasted" % (obj.name))
225 return {'FINISHED'}
228 class MUV_CPUVObjPasteUVMenu(bpy.types.Menu):
230 Menu class: Paste UV coordinate per object
233 bl_idname = "object.muv_cpuv_obj_paste_uv_menu"
234 bl_label = "Paste UV"
235 bl_description = "Paste UV coordinate per object"
237 def draw(self, context):
238 sc = context.scene
239 layout = self.layout
240 # create sub menu
241 uv_maps = []
242 for obj in bpy.data.objects:
243 if hasattr(obj.data, "uv_textures") and obj.select:
244 uv_maps.extend(obj.data.uv_textures.keys())
245 uv_maps = list(set(uv_maps))
246 ops = layout.operator(MUV_CPUVObjPasteUV.bl_idname, text="[Default]")
247 ops.uv_map = ""
248 ops.copy_seams = sc.muv_cpuv_copy_seams
249 for m in uv_maps:
250 ops = layout.operator(MUV_CPUVObjPasteUV.bl_idname, text=m)
251 ops.uv_map = m
252 ops.copy_seams = sc.muv_cpuv_copy_seams