]> git.mxchange.org Git - flightgear.git/blob - utils/Modeller/uv_pack.py
6cd1918ed9ee7b8ee6e44f5d4de8300ed9d758b8
[flightgear.git] / utils / Modeller / uv_pack.py
1 #!BPY
2
3 # """
4 # Name: 'Pack selected objects on a square'
5 # Blender: 245
6 # Group: 'UV'
7 # Tooltip: 'Pack UV maps of all selected objects onto an empty square texture'
8 # """
9
10 __author__ = "Melchior FRANZ < mfranz # aon : at >"
11 __url__ = "http://members.aon.at/mfranz/flightgear/"
12 __version__ = "0.1"
13 __bpydoc__ = """\
14 Script for mapping multiple objects onto one square texture.
15
16 Usage:
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
20     other object mappings
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
24
25     [now the texture image will first be erased, then colored rectangles
26     will appear for each object]
27
28 (6) rescale and/or remap objects that you aren't happy with (the
29     relative size of a mapping will be kept)
30
31     [continue with (5) until you like the result]
32
33 (7) export UV layout to SVG (UVs->Scripts->Save UV Face Layout)
34 """
35
36 MARGIN = 10 # px
37 GAP = 10    # px
38
39
40 import Blender, math, random
41
42
43 class Abort(Exception):
44         def __init__(self, msg):
45                 self.msg = msg
46
47
48 def pack():
49         image = Blender.Image.GetCurrent()
50         if not image:
51                 raise Abort('No texture image selected')
52
53         imgwidth, imgheight = image.getSize()
54         if imgwidth != imgheight:
55                 Blender.Draw.PupMenu("Warning%t|Image isn't a square!")
56         gap = (float(GAP) / imgwidth, float(GAP) / imgheight)
57         margin = (float(MARGIN) / imgwidth - gap[0] * 0.5, float(MARGIN) / imgheight - gap[1] * 0.5)
58
59         def drawrect(x0, y0, x1, y1, color = (255, 255, 255, 255)):
60                 x0 *= imgwidth
61                 x1 *= imgwidth
62                 y0 *= imgheight
63                 y1 *= imgheight
64                 for u in range(int(x0 + 0.5), int(x1 - 0.5)):
65                         for v in range(int(y0 + 0.5), int(y1 - 0.5)):
66                                 image.setPixelI(u, v, color)
67
68
69         boxes = []
70         meshes = {}
71
72         BIG = 1<<30
73         Blender.Window.DrawProgressBar(0.0, "packing")
74         for o in Blender.Scene.GetCurrent().objects.selected:
75                 if o.type != "Mesh":
76                         continue
77
78                 mesh = o.getData(mesh = 1)
79                 if not mesh.faceUV:
80                         continue
81                 if mesh.name in meshes:
82                         #print "dropping duplicate mesh", mesh.name, "of object", o.name
83                         continue
84                 meshes[mesh.name] = True
85
86                 print "\tobject '%s'" % o.name
87                 xmin = ymin = BIG
88                 xmax = ymax = -BIG
89                 for f in mesh.faces:
90                         for p in f.uv:
91                                 xmin = min(xmin, p[0])
92                                 xmax = max(xmax, p[0])
93                                 ymin = min(ymin, p[1])
94                                 ymax = max(ymax, p[1])
95
96                 width = xmax - xmin
97                 height = ymax - ymin
98                 boxes.append([0, 0, width + gap[0], height + gap[1], xmin, ymin, mesh])
99
100         if not boxes:
101                 raise Abort('No mesh objects selected')
102
103
104         boxwidth, boxheight = Blender.Geometry.BoxPack2D(boxes)
105         boxmax = max(boxwidth, boxheight)
106         xscale = (1.0 - 2.0 * margin[0]) / boxmax
107         yscale = (1.0 - 2.0 * margin[1]) / boxmax
108
109         Blender.Window.DrawProgressBar(0.2, "Erasing texture")
110         drawrect(0, 0, 1, 1) # erase texture
111         for box in boxes:
112                 xmin = ymin = BIG
113                 xmax = ymax = -BIG
114                 for f in box[6].faces:
115                         for p in f.uv:
116                                 p[0] = (p[0] - box[4] + box[0] + gap[0] * 0.5 + margin[0]) * xscale
117                                 p[1] = (p[1] - box[5] + box[1] + gap[1] * 0.5 + margin[1]) * yscale
118
119                                 xmin = min(xmin, p[0])
120                                 xmax = max(xmax, p[0])
121                                 ymin = min(ymin, p[1])
122                                 ymax = max(ymax, p[1])
123
124                 drawrect(xmin, ymin, xmax, ymax, (random.randint(128, 255), random.randint(128, 255),
125                                 random.randint(128, 255), 255))
126                 box[6].update()
127
128         Blender.Window.RedrawAll()
129         Blender.Window.DrawProgressBar(1.0, "Finished")
130
131
132
133 editmode = Blender.Window.EditMode()
134 if editmode:
135         Blender.Window.EditMode(0)
136 Blender.Window.WaitCursor(1)
137
138 try:
139         print "box packing ..."
140         pack()
141         print "done\n"
142 except Abort, e:
143         print "Error:", e.msg, "  -> aborting ...\n"
144         Blender.Draw.PupMenu("Error%t|" + e.msg)
145
146 Blender.Window.WaitCursor(0)
147 if editmode:
148         Blender.Window.EditMode(1)
149
150