Skip to content

Commit

Permalink
Added "grid" texture packer option for packing spritesheets with a un…
Browse files Browse the repository at this point in the history
…iform grid.
  • Loading branch information
NathanSweet committed Jan 25, 2014
1 parent ea289c6 commit cf1ece3
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/

package com.badlogic.gdx.tools.imagepacker;

import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Packer;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Page;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Rect;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Settings;
import com.badlogic.gdx.utils.Array;

import java.util.Collections;

/** @author Nathan Sweet */
public class GridPacker implements Packer {
private Settings settings;

public GridPacker (Settings settings) {
this.settings = settings;
}

public Array<Page> pack (Array<Rect> inputRects) {
System.out.print("Packing");

int cellWidth = 0, cellHeight = 0;
for (int i = 0, nn = inputRects.size; i < nn; i++) {
Rect rect = inputRects.get(i);
cellWidth = Math.max(cellWidth, rect.width);
cellHeight = Math.max(cellHeight, rect.height);
}
cellWidth += settings.paddingX;
cellHeight += settings.paddingY;

inputRects.reverse();

Array<Page> pages = new Array();
while (inputRects.size > 0) {
Page result = packPage(inputRects, cellWidth, cellHeight);
pages.add(result);
}
return pages;
}

private Page packPage (Array<Rect> inputRects, int cellWidth, int cellHeight) {
Page page = new Page();
page.outputRects = new Array();

int maxWidth = settings.maxWidth, maxHeight = settings.maxHeight;
if (settings.edgePadding) {
maxWidth -= settings.paddingX;
maxHeight -= settings.paddingY;
}
int x = 0, y = 0;
for (int i = inputRects.size - 1; i >= 0; i--) {
if (x + cellWidth > maxWidth) {
y += cellHeight;
if (y > maxHeight - cellHeight) break;
x = 0;
}
Rect rect = inputRects.removeIndex(i);
rect.x = x;
rect.y = y;
rect.width += settings.paddingX;
rect.height += settings.paddingY;
page.outputRects.add(rect);
x += cellWidth;
page.width = Math.max(page.width, x);
page.height = Math.max(page.height, y + cellHeight);
}

// Flip so rows start at top.
for (int i = page.outputRects.size - 1; i >= 0; i--) {
Rect rect = page.outputRects.get(i);
rect.y = page.height - rect.y - rect.height;
}
return page;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.badlogic.gdx.tools.imagepacker;

import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Packer;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Page;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Rect;
import com.badlogic.gdx.tools.imagepacker.TexturePacker2.Settings;
Expand All @@ -28,7 +29,7 @@
/** Packs pages of images using the maximal rectangles bin packing algorithm by Jukka Jylänki. A brute force binary search is used
* to pack into the smallest bin possible.
* @author Nathan Sweet */
public class MaxRectsPacker {
public class MaxRectsPacker implements Packer {
private RectComparator rectComparator = new RectComparator();
private FreeRectChoiceHeuristic[] methods = FreeRectChoiceHeuristic.values();
private MaxRects maxRects = new MaxRects();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
/** @author Nathan Sweet */
public class TexturePacker2 {
private final Settings settings;
private final MaxRectsPacker maxRectsPacker;
private final Packer packer;
private final ImageProcessor imageProcessor;

/** @param rootDir Can be null. */
Expand All @@ -60,7 +60,10 @@ public TexturePacker2 (File rootDir, Settings settings) {
throw new RuntimeException("If pot is true, maxHeight must be a power of two: " + settings.maxHeight);
}

maxRectsPacker = new MaxRectsPacker(settings);
if (settings.grid)
packer = new GridPacker(settings);
else
packer = new MaxRectsPacker(settings);
imageProcessor = new ImageProcessor(rootDir, settings);
}

Expand All @@ -81,7 +84,7 @@ public void pack (File outputDir, String packFileName) {

if (packFileName.indexOf('.') == -1) packFileName += ".atlas";

Array<Page> pages = maxRectsPacker.pack(imageProcessor.getImages());
Array<Page> pages = packer.pack(imageProcessor.getImages());
writeImages(outputDir, pages, packFileName);
try {
writePackFile(outputDir, pages, packFileName);
Expand Down Expand Up @@ -380,7 +383,8 @@ public void apply (Rect rect) {
static public class Rect {
public String name;
public int offsetX, offsetY, regionWidth, regionHeight, originalWidth, originalHeight;
public int x, y, width, height; // Portion of page taken by this region, including padding.
public int x, y;
public int width, height; // Portion of page taken by this region, including padding.
public int index;
public boolean rotated;
public Set<Alias> aliases = new HashSet<Alias>();
Expand Down Expand Up @@ -512,6 +516,7 @@ static public class Settings {
public boolean useIndexes = true;
public boolean bleed = true;
public boolean limitMemory = true;
public boolean grid;

public Settings () {
}
Expand Down Expand Up @@ -562,11 +567,10 @@ static public void process (String input, String output, String packFileName) {
* @param packFileName The name of the pack file. Also used to name the page images. */
static public void process (Settings settings, String input, String output, String packFileName) {
try {
TexturePackerFileProcessor processor =
new TexturePackerFileProcessor(settings, packFileName);
TexturePackerFileProcessor processor = new TexturePackerFileProcessor(settings, packFileName);
// Sort input files by name to avoid platform-dependent atlas output changes.
processor.setComparator(new Comparator<File>() {
public int compare(File file1, File file2) {
public int compare (File file1, File file2) {
return file1.getName().compareTo(file2.getName());
}
});
Expand Down Expand Up @@ -598,6 +602,10 @@ static public void processIfModified (Settings settings, String input, String ou
if (isModified(input, output, packFileName)) process(settings, input, output, packFileName);
}

static public interface Packer {
public Array<Page> pack (Array<Rect> inputRects);
}

static public void main (String[] args) throws Exception {
String input = null, output = null, packFileName = "pack.atlas";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/** @author Nathan Sweet */
Expand Down Expand Up @@ -150,6 +151,44 @@ protected void processFile (Entry entry) {

if (files.isEmpty()) return;

// Sort by name using numeric suffix, then alpha.
Collections.sort(files, new Comparator<Entry>() {
final Pattern digitSuffix = Pattern.compile("(.*?)(\\d+)$");

public int compare (Entry entry1, Entry entry2) {
String full1 = entry1.inputFile.getName();
int dotIndex = full1.lastIndexOf('.');
if (dotIndex != -1) full1 = full1.substring(0, dotIndex);

String full2 = entry2.inputFile.getName();
dotIndex = full2.lastIndexOf('.');
if (dotIndex != -1) full2 = full2.substring(0, dotIndex);

String name1 = full1, name2 = full2;
int num1 = 0, num2 = 0;

Matcher matcher = digitSuffix.matcher(full1);
if (matcher.matches()) {
try {
num1 = Integer.parseInt(matcher.group(2));
name1 = matcher.group(1);
} catch (Exception ignored) {
}
}
matcher = digitSuffix.matcher(full2);
if (matcher.matches()) {
try {
num2 = Integer.parseInt(matcher.group(2));
name2 = matcher.group(1);
} catch (Exception ignored) {
}
}
int compare = name1.compareTo(name2);
if (compare != 0 || num1 == num2) return compare;
return num1 - num2;
}
});

// Pack.
System.out.println(inputDir.inputFile.getName());
TexturePacker2 packer = new TexturePacker2(root, settings);
Expand Down

0 comments on commit cf1ece3

Please sign in to comment.