]> git.mxchange.org Git - flightgear.git/blob - utils/Modeller/uv_pack.py
- improve Blender registry handling
[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
41 from random import randint as rand
42
43
44 class Abort(Exception):
45         def __init__(self, msg):
46                 self.msg = msg
47
48
49 def pack():
50         image = Blender.Image.GetCurrent()
51         if not image:
52                 raise Abort('No texture image selected')
53
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)
59
60         def drawrect(x0, y0, x1, y1, color = (255, 255, 255, 255)):
61                 x0 *= imgwidth
62                 x1 *= imgwidth
63                 y0 *= imgheight
64                 y1 *= imgheight
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)
68
69
70         boxes = []
71         unique_meshes = {}
72
73         BIG = 1<<30
74         Blender.Window.DrawProgressBar(0.0, "packing")
75         for o in Blender.Scene.GetCurrent().objects.selected:
76                 if o.type != "Mesh":
77                         continue
78
79                 mesh = o.getData(mesh = 1)
80                 if not mesh.faceUV:
81                         continue
82                 if mesh.name in unique_meshes:
83                         #print "dropping duplicate mesh", mesh.name, "of object", o.name
84                         continue
85                 unique_meshes[mesh.name] = True
86
87                 print "\tobject '%s'" % o.name
88                 xmin = ymin = BIG
89                 xmax = ymax = -BIG
90                 for f in mesh.faces:
91                         for p in f.uv:
92                                 xmin = min(xmin, p[0])
93                                 xmax = max(xmax, p[0])
94                                 ymin = min(ymin, p[1])
95                                 ymax = max(ymax, p[1])
96
97                 width = xmax - xmin
98                 height = ymax - ymin
99                 boxes.append([0, 0, width + gap[0], height + gap[1], xmin, ymin, mesh])
100
101         if not boxes:
102                 raise Abort('No mesh objects selected')
103
104
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
109
110         image.reload()
111         #drawrect(0, 0, 1, 1) # erase texture
112
113         for i, box in enumerate(boxes):
114                 Blender.Window.DrawProgressBar(float(i) * len(boxes), "Drawing")
115                 xmin = ymin = BIG
116                 xmax = ymax = -BIG
117                 for f in box[6].faces:
118                         for p in f.uv:
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
121
122                                 xmin = min(xmin, p[0])
123                                 xmax = max(xmax, p[0])
124                                 ymin = min(ymin, p[1])
125                                 ymax = max(ymax, p[1])
126
127                 drawrect(xmin, ymin, xmax, ymax, (rand(128, 255), rand(128, 255), rand(128, 255), 255))
128                 box[6].update()
129
130         Blender.Window.RedrawAll()
131         Blender.Window.DrawProgressBar(1.0, "Finished")
132
133
134
135 editmode = Blender.Window.EditMode()
136 if editmode:
137         Blender.Window.EditMode(0)
138 Blender.Window.WaitCursor(1)
139
140 try:
141         print "box packing ..."
142         pack()
143         print "done\n"
144 except Abort, e:
145         print "Error:", e.msg, "  -> aborting ...\n"
146         Blender.Draw.PupMenu("Error%t|" + e.msg)
147
148 Blender.Window.WaitCursor(0)
149 if editmode:
150         Blender.Window.EditMode(1)
151
152