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)
41 from random import randint as rand
44 class Abort(Exception):
45 def __init__(self, msg):
50 image = Blender.Image.GetCurrent()
52 raise Abort('No texture image selected')
54 imgwidth, imgheight = image.getSize()
55 if imgwidth != imgheight:
56 Blender.Draw.PupMenu("Warning%t|Image isn't a square!")
57 gap = (float(GAP) / imgwidth, float(GAP) / imgheight)
58 margin = (float(MARGIN) / imgwidth - gap[0] * 0.5, float(MARGIN) / imgheight - gap[1] * 0.5)
60 def drawrect(x0, y0, x1, y1, color = (255, 255, 255, 255)):
65 for u in range(int(x0 + 0.5), int(x1 - 0.5)):
66 for v in range(int(y0 + 0.5), int(y1 - 0.5)):
67 image.setPixelI(u, v, color)
74 Blender.Window.DrawProgressBar(0.0, "packing")
75 for o in Blender.Scene.GetCurrent().objects.selected:
79 mesh = o.getData(mesh = 1)
82 if mesh.name in unique_meshes:
83 #print "dropping duplicate mesh", mesh.name, "of object", o.name
85 unique_meshes[mesh.name] = True
87 print "\tobject '%s'" % o.name
92 xmin = min(xmin, p[0])
93 xmax = max(xmax, p[0])
94 ymin = min(ymin, p[1])
95 ymax = max(ymax, p[1])
99 boxes.append([0, 0, width + gap[0], height + gap[1], xmin, ymin, mesh])
102 raise Abort('No mesh objects selected')
105 boxwidth, boxheight = Blender.Geometry.BoxPack2D(boxes)
106 boxmax = max(boxwidth, boxheight)
107 xscale = (1.0 - 2.0 * margin[0]) / boxmax
108 yscale = (1.0 - 2.0 * margin[1]) / boxmax
111 #drawrect(0, 0, 1, 1) # erase texture
113 for i, box in enumerate(boxes):
114 Blender.Window.DrawProgressBar(float(i) * len(boxes), "Drawing")
117 for f in box[6].faces:
119 p[0] = (p[0] - box[4] + box[0] + gap[0] * 0.5 + margin[0]) * xscale
120 p[1] = (p[1] - box[5] + box[1] + gap[1] * 0.5 + margin[1]) * yscale
122 xmin = min(xmin, p[0])
123 xmax = max(xmax, p[0])
124 ymin = min(ymin, p[1])
125 ymax = max(ymax, p[1])
127 drawrect(xmin, ymin, xmax, ymax, (rand(128, 255), rand(128, 255), rand(128, 255), 255))
130 Blender.Window.RedrawAll()
131 Blender.Window.DrawProgressBar(1.0, "Finished")
135 editmode = Blender.Window.EditMode()
137 Blender.Window.EditMode(0)
138 Blender.Window.WaitCursor(1)
141 print "box packing ..."
145 print "Error:", e.msg, " -> aborting ...\n"
146 Blender.Draw.PupMenu("Error%t|" + e.msg)
148 Blender.Window.WaitCursor(0)
150 Blender.Window.EditMode(1)