4 # Name: 'Pack selected objects on a square'
7 # Tooltip: 'Pack UV maps of all selected objects onto an empty square texture'
10 __author__ = "Melchior FRANZ < mfranz # aon : at >"
11 __url__ = "http://members.aon.at/mfranz/flightgear/"
14 Script for mapping multiple objects onto one square texture.
17 (1) create new square texture in the UV editor
18 (2) map all objects individually, choosing the most appropriate technique
19 (3) scale each of the mappings to the appropriate size, relative to the
21 (4) select all objects and switch to edit mode (consider to use
22 Select->Linked->Material or similar methods)
23 (5) start this script with UVs->Scripts->Pack objects on a square
25 [now the texture image will first be erased, then colored rectangles
26 will appear for each object]
28 (6) rescale and/or remap objects that you aren't happy with (the
29 relative size of a mapping will be kept)
31 [continue with (5) until you like the result]
33 (7) export UV layout to SVG (UVs->Scripts->Save UV Face Layout)
37 #--------------------------------------------------------------------------------
38 # Copyright (C) 2008 Melchior FRANZ < mfranz # aon : at >
40 # This program is free software; you can redistribute it and/or
41 # modify it under the terms of the GNU General Public License as
42 # published by the Free Software Foundation; either version 2 of the
43 # License, or (at your option) any later version.
45 # This program is distributed in the hope that it will be useful, but
46 # WITHOUT ANY WARRANTY; without even the implied warranty of
47 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
48 # General Public License for more details.
50 # You should have received a copy of the GNU General Public License
51 # along with this program; if not, write to the Free Software
52 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
53 #--------------------------------------------------------------------------------
61 from random import randint as rand
64 class Abort(Exception):
65 def __init__(self, msg):
70 image = Blender.Image.GetCurrent()
72 raise Abort('No texture image selected')
74 imgwidth, imgheight = image.getSize()
75 if imgwidth != imgheight:
76 Blender.Draw.PupMenu("Warning%t|Image isn't a square!")
77 gap = (float(GAP) / imgwidth, float(GAP) / imgheight)
78 margin = (float(MARGIN) / imgwidth - gap[0] * 0.5, float(MARGIN) / imgheight - gap[1] * 0.5)
80 def drawrect(x0, y0, x1, y1, color = (255, 255, 255, 255)):
85 for u in range(int(x0 + 0.5), int(x1 - 0.5)):
86 for v in range(int(y0 + 0.5), int(y1 - 0.5)):
87 image.setPixelI(u, v, color)
94 Blender.Window.DrawProgressBar(0.0, "packing")
95 for o in Blender.Scene.GetCurrent().objects.selected:
99 mesh = o.getData(mesh = 1)
102 if mesh.name in unique_meshes:
103 #print "dropping duplicate mesh", mesh.name, "of object", o.name
105 unique_meshes[mesh.name] = True
107 print "\tobject '%s'" % o.name
112 xmin = min(xmin, p[0])
113 xmax = max(xmax, p[0])
114 ymin = min(ymin, p[1])
115 ymax = max(ymax, p[1])
119 boxes.append([0, 0, width + gap[0], height + gap[1], xmin, ymin, mesh])
122 raise Abort('No mesh objects selected')
125 boxwidth, boxheight = Blender.Geometry.BoxPack2D(boxes)
126 boxmax = max(boxwidth, boxheight)
127 xscale = (1.0 - 2.0 * margin[0]) / boxmax
128 yscale = (1.0 - 2.0 * margin[1]) / boxmax
131 #drawrect(0, 0, 1, 1) # erase texture
133 for i, box in enumerate(boxes):
134 Blender.Window.DrawProgressBar(float(i) * len(boxes), "Drawing")
137 for f in box[6].faces:
139 p[0] = (p[0] - box[4] + box[0] + gap[0] * 0.5 + margin[0]) * xscale
140 p[1] = (p[1] - box[5] + box[1] + gap[1] * 0.5 + margin[1]) * yscale
142 xmin = min(xmin, p[0])
143 xmax = max(xmax, p[0])
144 ymin = min(ymin, p[1])
145 ymax = max(ymax, p[1])
147 drawrect(xmin, ymin, xmax, ymax, (rand(128, 255), rand(128, 255), rand(128, 255), 255))
150 Blender.Window.RedrawAll()
151 Blender.Window.DrawProgressBar(1.0, "Finished")
155 editmode = Blender.Window.EditMode()
157 Blender.Window.EditMode(0)
158 Blender.Window.WaitCursor(1)
161 print "box packing ..."
165 print "Error:", e.msg, " -> aborting ...\n"
166 Blender.Draw.PupMenu("Error%t|" + e.msg)
168 Blender.Window.WaitCursor(0)
170 Blender.Window.EditMode(1)