try to avoid long-skinny areas

This commit is contained in:
David Rose 2009-02-06 21:58:00 +00:00
parent cec1dbfc00
commit 1c6893bfde

View File

@ -622,7 +622,7 @@ class TexMemWatcher(DirectObject):
# Sort the regions from largest to smallest to maximize # Sort the regions from largest to smallest to maximize
# packing effectiveness. # packing effectiveness.
texRecords = self.texRecordsByTex.values() texRecords = self.texRecordsByTex.values()
texRecords.sort(key = lambda tr: (-tr.w, -tr.h)) texRecords.sort(key = lambda tr: (tr.w, tr.h), reverse = True)
self.overflowing = False self.overflowing = False
for tr in texRecords: for tr in texRecords:
@ -671,7 +671,7 @@ class TexMemWatcher(DirectObject):
# Couldn't find a hole of the right shape; can we find a # Couldn't find a hole of the right shape; can we find a
# single rectangular hole of the right area, but of any shape? # single rectangular hole of the right area, but of any shape?
tp = self.findArea(tr.h * tr.w) tp = self.findArea(tr.w, tr.h)
if tp: if tp:
texCmp = cmp(tr.w, tr.h) texCmp = cmp(tr.w, tr.h)
holeCmp = cmp(tp.p[1] - tp.p[0], tp.p[3] - tp.p[2]) holeCmp = cmp(tp.p[1] - tp.p[0], tp.p[3] - tp.p[2])
@ -687,10 +687,14 @@ class TexMemWatcher(DirectObject):
# in. # in.
tpList = self.findHolePieces(tr.h * tr.w) tpList = self.findHolePieces(tr.h * tr.w)
if tpList: if tpList:
texCmp = cmp(tr.w, tr.h)
tr.placements = tpList tr.placements = tpList
tr.makeCard(self)
for tp in tpList: for tp in tpList:
holeCmp = cmp(tp.p[1] - tp.p[0], tp.p[3] - tp.p[2])
if texCmp != 0 and holeCmp != 0 and texCmp != holeCmp:
tp.rotated = True
self.texPlacements[tp] = tr self.texPlacements[tp] = tr
tr.makeCard(self)
return return
# Just let it overflow. # Just let it overflow.
@ -752,13 +756,60 @@ class TexMemWatcher(DirectObject):
# Nope, wouldn't fit anywhere. # Nope, wouldn't fit anywhere.
return None return None
def findArea(self, w, h):
def findArea(self, area):
""" Searches for a rectangular hole that is at least area """ Searches for a rectangular hole that is at least area
square units big, regardless of its shape. If one is found, square units big, regardless of its shape, but attempt to find
returns an appropriate TexPlacement; otherwise, returns one that comes close to the right shape, at least. If one is
found, returns an appropriate TexPlacement; otherwise, returns
None. """ None. """
aspect = float(min(w, h)) / float(max(w, h))
area = w * h
holes = self.findAvailableHoles(area)
# Walk through the list and find the one with the best aspect
# match.
matches = []
for tarea, tp in holes:
l, r, b, t = tp.p
tw = r - l
th = t - b
# To constrain our area within this rectangle, how would
# we have to squish it?
if tw < w:
# We'd have to make it taller.
nh = area / tw
assert nh <= th
th = nh
elif th < h:
# We'd have to make it narrower.
nw = area / th
assert nw <= tw
tw = nw
else:
# We don't have to squish it? Shouldn't have gotten
# here.
assert False
# Make a new tp that has the right area.
tp = TexPlacement(l, l + tw, b, b + th)
ta = float(min(tw, th)) / float(max(tw, th))
match = min(ta, aspect) / max(ta, aspect)
matches.append((match, tp))
if matches:
return max(matches)[1]
return None
def findAllArea(self, area):
""" Searches for a rectangular hole that is at least area
square units big, regardless of its shape. Returns a list of
all such holes found. """
result = []
y = 0 y = 0
while y < self.h: while y < self.h:
nextY = self.h nextY = self.h
@ -782,8 +833,7 @@ class TexMemWatcher(DirectObject):
tp = TexPlacement(x, x + tpw, y, y + tph) tp = TexPlacement(x, x + tpw, y, y + tph)
overlap = self.findOverlap(tp) overlap = self.findOverlap(tp)
if not overlap: if not overlap:
# Hooray! result.append(tp)
return tp
nextX = min(nextX, overlap.p[1]) nextX = min(nextX, overlap.p[1])
nextY = min(nextY, overlap.p[3]) nextY = min(nextY, overlap.p[3])
@ -803,8 +853,7 @@ class TexMemWatcher(DirectObject):
assert nextY > y assert nextY > y
y = nextY y = nextY
# Nope, wouldn't fit anywhere. return result
return None
def findHolePieces(self, area): def findHolePieces(self, area):
""" Returns a list of holes whose net area sums to the given """ Returns a list of holes whose net area sums to the given
@ -841,7 +890,13 @@ class TexMemWatcher(DirectObject):
return None return None
def findLargestHole(self): def findLargestHole(self):
""" Searches for the largest available hole. """ holes = self.findAvailableHoles(0)
return max(holes)[1]
def findAvailableHoles(self, area):
""" Finds a list of available holes, of at least the indicated
area. Returns a list of tuples, where each tuple is of the
form (area, tp)."""
holes = [] holes = []
@ -869,7 +924,9 @@ class TexMemWatcher(DirectObject):
overlap = self.findOverlap(tp) overlap = self.findOverlap(tp)
if not overlap: if not overlap:
# Here's a hole. # Here's a hole.
holes.append((tpw * tph, tp)) tarea = tpw * tph
if tarea >= area:
holes.append((tarea, tp))
break break
nextX = min(nextX, overlap.p[1]) nextX = min(nextX, overlap.p[1])
@ -901,12 +958,7 @@ class TexMemWatcher(DirectObject):
assert nextY > y assert nextY > y
y = nextY y = nextY
if not holes: return holes
# No holes to be found.
return None
# Return the biggest hole
return max(holes)[1]
def findOverlap(self, tp): def findOverlap(self, tp):
""" If there is another placement that overlaps the indicated """ If there is another placement that overlaps the indicated