1
0
Fork 0
flightgear/utils/Modeller/uv_pack.py
mfranz 7a6376021a - make it faster by reloading rather than erasing the image every time
(this also fixes a bug that wouldn't update a changed texture in 3D view)
- better progress bar
2008-03-03 18:06:57 +00:00

153 lines
3.9 KiB
Python

#!BPY
# """
# Name: 'Pack selected objects on a square'
# Blender: 245
# Group: 'UV'
# Tooltip: 'Pack UV maps of all selected objects onto an empty square texture'
# """
__author__ = "Melchior FRANZ < mfranz # aon : at >"
__url__ = "http://members.aon.at/mfranz/flightgear/"
__version__ = "0.1"
__bpydoc__ = """\
Script for mapping multiple objects onto one square texture.
Usage:
(1) create new square texture in the UV editor
(2) map all objects individually, choosing the most appropriate technique
(3) scale each of the mappings to the appropriate size, relative to the
other object mappings
(4) select all objects and switch to edit mode (consider to use
Select->Linked->Material or similar methods)
(5) start this script with UVs->Scripts->Pack objects on a square
[now the texture image will first be erased, then colored rectangles
will appear for each object]
(6) rescale and/or remap objects that you aren't happy with (the
relative size of a mapping will be kept)
[continue with (5) until you like the result]
(7) export UV layout to SVG (UVs->Scripts->Save UV Face Layout)
"""
MARGIN = 10 # px
GAP = 10 # px
import Blender
from random import randint as rand
class Abort(Exception):
def __init__(self, msg):
self.msg = msg
def pack():
image = Blender.Image.GetCurrent()
if not image:
raise Abort('No texture image selected')
imgwidth, imgheight = image.getSize()
if imgwidth != imgheight:
Blender.Draw.PupMenu("Warning%t|Image isn't a square!")
gap = (float(GAP) / imgwidth, float(GAP) / imgheight)
margin = (float(MARGIN) / imgwidth - gap[0] * 0.5, float(MARGIN) / imgheight - gap[1] * 0.5)
def drawrect(x0, y0, x1, y1, color = (255, 255, 255, 255)):
x0 *= imgwidth
x1 *= imgwidth
y0 *= imgheight
y1 *= imgheight
for u in range(int(x0 + 0.5), int(x1 - 0.5)):
for v in range(int(y0 + 0.5), int(y1 - 0.5)):
image.setPixelI(u, v, color)
boxes = []
unique_meshes = {}
BIG = 1<<30
Blender.Window.DrawProgressBar(0.0, "packing")
for o in Blender.Scene.GetCurrent().objects.selected:
if o.type != "Mesh":
continue
mesh = o.getData(mesh = 1)
if not mesh.faceUV:
continue
if mesh.name in unique_meshes:
#print "dropping duplicate mesh", mesh.name, "of object", o.name
continue
unique_meshes[mesh.name] = True
print "\tobject '%s'" % o.name
xmin = ymin = BIG
xmax = ymax = -BIG
for f in mesh.faces:
for p in f.uv:
xmin = min(xmin, p[0])
xmax = max(xmax, p[0])
ymin = min(ymin, p[1])
ymax = max(ymax, p[1])
width = xmax - xmin
height = ymax - ymin
boxes.append([0, 0, width + gap[0], height + gap[1], xmin, ymin, mesh])
if not boxes:
raise Abort('No mesh objects selected')
boxwidth, boxheight = Blender.Geometry.BoxPack2D(boxes)
boxmax = max(boxwidth, boxheight)
xscale = (1.0 - 2.0 * margin[0]) / boxmax
yscale = (1.0 - 2.0 * margin[1]) / boxmax
Blender.Window.DrawProgressBar(0.2, "Erasing texture")
image.reload()
#drawrect(0, 0, 1, 1) # erase texture
for i, box in enumerate(boxes):
Blender.Window.DrawProgressBar(i * 0.8 / len(boxes), "Drawing")
xmin = ymin = BIG
xmax = ymax = -BIG
for f in box[6].faces:
for p in f.uv:
p[0] = (p[0] - box[4] + box[0] + gap[0] * 0.5 + margin[0]) * xscale
p[1] = (p[1] - box[5] + box[1] + gap[1] * 0.5 + margin[1]) * yscale
xmin = min(xmin, p[0])
xmax = max(xmax, p[0])
ymin = min(ymin, p[1])
ymax = max(ymax, p[1])
drawrect(xmin, ymin, xmax, ymax, (rand(128, 255), rand(128, 255), rand(128, 255), 255))
box[6].update()
Blender.Window.RedrawAll()
Blender.Window.DrawProgressBar(1.0, "Finished")
editmode = Blender.Window.EditMode()
if editmode:
Blender.Window.EditMode(0)
Blender.Window.WaitCursor(1)
try:
print "box packing ..."
pack()
print "done\n"
except Abort, e:
print "Error:", e.msg, " -> aborting ...\n"
Blender.Draw.PupMenu("Error%t|" + e.msg)
Blender.Window.WaitCursor(0)
if editmode:
Blender.Window.EditMode(1)