gdx-studio

#libgdx#java#desktop

git clone https://git.pyrossh.dev/gdx-studio

An IDE for creating Games using libgdx and Java supported on all platforms Android, iOS, Desktop


src_libs/com/badlogic/gdx/tools/imagepacker/TexturePacker2.java
a62d533 1
/*******************************************************************************
a62d533 2
 * Copyright 2011 See AUTHORS file.
a62d533 3
 * 
a62d533 4
 * Licensed under the Apache License, Version 2.0 (the "License");
a62d533 5
 * you may not use this file except in compliance with the License.
a62d533 6
 * You may obtain a copy of the License at
a62d533 7
 * 
a62d533 8
 *   http://www.apache.org/licenses/LICENSE-2.0
a62d533 9
 * 
a62d533 10
 * Unless required by applicable law or agreed to in writing, software
a62d533 11
 * distributed under the License is distributed on an "AS IS" BASIS,
a62d533 12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
a62d533 13
 * See the License for the specific language governing permissions and
a62d533 14
 * limitations under the License.
a62d533 15
 ******************************************************************************/
a62d533 16
a62d533 17
package com.badlogic.gdx.tools.imagepacker;
a62d533 18
a62d533 19
import java.awt.Color;
a62d533 20
import java.awt.Graphics2D;
a62d533 21
import java.awt.image.BufferedImage;
a62d533 22
import java.io.File;
a62d533 23
import java.io.FileWriter;
a62d533 24
import java.io.IOException;
a62d533 25
import java.util.HashSet;
a62d533 26
import java.util.Iterator;
a62d533 27
import java.util.Set;
a62d533 28
a62d533 29
import javax.imageio.IIOImage;
a62d533 30
import javax.imageio.ImageIO;
a62d533 31
import javax.imageio.ImageWriteParam;
a62d533 32
import javax.imageio.ImageWriter;
a62d533 33
import javax.imageio.stream.ImageOutputStream;
a62d533 34
a62d533 35
import com.badlogic.gdx.files.FileHandle;
a62d533 36
import com.badlogic.gdx.graphics.Pixmap.Format;
a62d533 37
import com.badlogic.gdx.graphics.Texture.TextureFilter;
a62d533 38
import com.badlogic.gdx.graphics.Texture.TextureWrap;
a62d533 39
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData;
a62d533 40
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData.Region;
a62d533 41
import com.badlogic.gdx.math.MathUtils;
a62d533 42
import com.badlogic.gdx.utils.Array;
a62d533 43
import com.badlogic.gdx.utils.GdxRuntimeException;
a62d533 44
a62d533 45
/** @author Nathan Sweet */
a62d533 46
public class TexturePacker2 {
a62d533 47
	private final Settings settings;
a62d533 48
	private final MaxRectsPacker maxRectsPacker;
a62d533 49
	private final ImageProcessor imageProcessor;
a62d533 50
a62d533 51
	/** @param rootDir Can be null. */
a62d533 52
	public TexturePacker2 (File rootDir, Settings settings) {
a62d533 53
		this.settings = settings;
a62d533 54
a62d533 55
		if (settings.pot) {
a62d533 56
			if (settings.maxWidth != MathUtils.nextPowerOfTwo(settings.maxWidth))
a62d533 57
				throw new RuntimeException("If pot is true, maxWidth must be a power of two: " + settings.maxWidth);
a62d533 58
			if (settings.maxHeight != MathUtils.nextPowerOfTwo(settings.maxHeight))
a62d533 59
				throw new RuntimeException("If pot is true, maxHeight must be a power of two: " + settings.maxHeight);
a62d533 60
		}
a62d533 61
a62d533 62
		maxRectsPacker = new MaxRectsPacker(settings);
a62d533 63
		imageProcessor = new ImageProcessor(rootDir, settings);
a62d533 64
	}
a62d533 65
a62d533 66
	public TexturePacker2 (Settings settings) {
a62d533 67
		this(null, settings);
a62d533 68
	}
a62d533 69
a62d533 70
	public void addImage (File file) {
a62d533 71
		imageProcessor.addImage(file);
a62d533 72
	}
a62d533 73
a62d533 74
	public void addImage (BufferedImage image, String name) {
a62d533 75
		imageProcessor.addImage(image, name);
a62d533 76
	}
a62d533 77
a62d533 78
	public void pack (File outputDir, String packFileName) {
a62d533 79
		outputDir.mkdirs();
a62d533 80
a62d533 81
		if (packFileName.indexOf('.') == -1) packFileName += ".atlas";
a62d533 82
a62d533 83
		Array<Page> pages = maxRectsPacker.pack(imageProcessor.getImages());
a62d533 84
		writeImages(outputDir, pages, packFileName);
a62d533 85
		try {
a62d533 86
			writePackFile(outputDir, pages, packFileName);
a62d533 87
		} catch (IOException ex) {
a62d533 88
			throw new RuntimeException("Error writing pack file.", ex);
a62d533 89
		}
a62d533 90
	}
a62d533 91
a62d533 92
	private void writeImages (File outputDir, Array<Page> pages, String packFileName) {
a62d533 93
		String imageName = packFileName;
a62d533 94
		int dotIndex = imageName.lastIndexOf('.');
a62d533 95
		if (dotIndex != -1) imageName = imageName.substring(0, dotIndex);
a62d533 96
a62d533 97
		int fileIndex = 0;
a62d533 98
		for (Page page : pages) {
a62d533 99
			int width = page.width, height = page.height;
a62d533 100
			int paddingX = settings.paddingX;
a62d533 101
			int paddingY = settings.paddingY;
a62d533 102
			if (settings.duplicatePadding) {
a62d533 103
				paddingX /= 2;
a62d533 104
				paddingY /= 2;
a62d533 105
			}
a62d533 106
			width -= settings.paddingX;
a62d533 107
			height -= settings.paddingY;
a62d533 108
			if (settings.edgePadding) {
a62d533 109
				page.x = paddingX;
a62d533 110
				page.y = paddingY;
a62d533 111
				width += paddingX * 2;
a62d533 112
				height += paddingY * 2;
a62d533 113
			}
a62d533 114
			if (settings.pot) {
a62d533 115
				width = MathUtils.nextPowerOfTwo(width);
a62d533 116
				height = MathUtils.nextPowerOfTwo(height);
a62d533 117
			}
a62d533 118
			width = Math.max(settings.minWidth, width);
a62d533 119
			height = Math.max(settings.minHeight, height);
a62d533 120
a62d533 121
			if (settings.forceSquareOutput) {
a62d533 122
				if (width > height) {
a62d533 123
					height = width;
a62d533 124
				} else {
a62d533 125
					width = height;
a62d533 126
				}
a62d533 127
			}
a62d533 128
a62d533 129
			File outputFile;
a62d533 130
			while (true) {
a62d533 131
				outputFile = new File(outputDir, imageName + (fileIndex++ == 0 ? "" : fileIndex) + "." + settings.outputFormat);
a62d533 132
				if (!outputFile.exists()) break;
a62d533 133
			}
a62d533 134
			page.imageName = outputFile.getName();
a62d533 135
a62d533 136
			BufferedImage canvas = new BufferedImage(width, height, getBufferedImageType(settings.format));
a62d533 137
			Graphics2D g = (Graphics2D)canvas.getGraphics();
a62d533 138
a62d533 139
			System.out.println("Writing " + canvas.getWidth() + "x" + canvas.getHeight() + ": " + outputFile);
a62d533 140
a62d533 141
			for (Rect rect : page.outputRects) {
a62d533 142
				BufferedImage image = rect.image;
a62d533 143
				int iw = image.getWidth();
a62d533 144
				int ih = image.getHeight();
a62d533 145
				int rectX = page.x + rect.x, rectY = page.y + page.height - rect.y - rect.height;
a62d533 146
				if (settings.duplicatePadding) {
a62d533 147
					int amountX = settings.paddingX / 2;
a62d533 148
					int amountY = settings.paddingY / 2;
a62d533 149
					if (rect.rotated) {
a62d533 150
						// Copy corner pixels to fill corners of the padding.
a62d533 151
						for (int i = 1; i <= amountX; i++) {
a62d533 152
							for (int j = 1; j <= amountY; j++) {
a62d533 153
								plot(canvas, rectX - j, rectY + iw - 1 + i, image.getRGB(0, 0));
a62d533 154
								plot(canvas, rectX + ih - 1 + j, rectY + iw - 1 + i, image.getRGB(0, ih - 1));
a62d533 155
								plot(canvas, rectX - j, rectY - i, image.getRGB(iw - 1, 0));
a62d533 156
								plot(canvas, rectX + ih - 1 + j, rectY - i, image.getRGB(iw - 1, ih - 1));
a62d533 157
							}
a62d533 158
						}
a62d533 159
						// Copy edge pixels into padding.
a62d533 160
						for (int i = 1; i <= amountY; i++) {
a62d533 161
							for (int j = 0; j < iw; j++) {
a62d533 162
								plot(canvas, rectX - i, rectY + iw - 1 - j, image.getRGB(j, 0));
a62d533 163
								plot(canvas, rectX + ih - 1 + i, rectY + iw - 1 - j, image.getRGB(j, ih - 1));
a62d533 164
							}
a62d533 165
						}
a62d533 166
						for (int i = 1; i <= amountX; i++) {
a62d533 167
							for (int j = 0; j < ih; j++) {
a62d533 168
								plot(canvas, rectX + j, rectY - i, image.getRGB(iw - 1, j));
a62d533 169
								plot(canvas, rectX + j, rectY + iw - 1 + i, image.getRGB(0, j));
a62d533 170
							}
a62d533 171
						}
a62d533 172
					} else {
a62d533 173
						// Copy corner pixels to fill corners of the padding.
a62d533 174
						for (int i = 1; i <= amountX; i++) {
a62d533 175
							for (int j = 1; j <= amountY; j++) {
a62d533 176
								canvas.setRGB(rectX - i, rectY - j, image.getRGB(0, 0));
a62d533 177
								canvas.setRGB(rectX - i, rectY + ih - 1 + j, image.getRGB(0, ih - 1));
a62d533 178
								canvas.setRGB(rectX + iw - 1 + i, rectY - j, image.getRGB(iw - 1, 0));
a62d533 179
								canvas.setRGB(rectX + iw - 1 + i, rectY + ih - 1 + j, image.getRGB(iw - 1, ih - 1));
a62d533 180
							}
a62d533 181
						}
a62d533 182
						// Copy edge pixels into padding.
a62d533 183
						for (int i = 1; i <= amountY; i++) {
a62d533 184
							copy(image, 0, 0, iw, 1, canvas, rectX, rectY - i, rect.rotated);
a62d533 185
							copy(image, 0, ih - 1, iw, 1, canvas, rectX, rectY + ih - 1 + i, rect.rotated);
a62d533 186
						}
a62d533 187
						for (int i = 1; i <= amountX; i++) {
a62d533 188
							copy(image, 0, 0, 1, ih, canvas, rectX - i, rectY, rect.rotated);
a62d533 189
							copy(image, iw - 1, 0, 1, ih, canvas, rectX + iw - 1 + i, rectY, rect.rotated);
a62d533 190
						}
a62d533 191
					}
a62d533 192
				}				
a62d533 193
				copy(image, 0, 0, iw, ih, canvas, rectX, rectY, rect.rotated);
a62d533 194
				if (settings.debug) {
a62d533 195
					g.setColor(Color.magenta);
a62d533 196
					g.drawRect(rectX, rectY, rect.width - settings.paddingX - 1, rect.height - settings.paddingY - 1);
a62d533 197
				}
a62d533 198
			}
a62d533 199
a62d533 200
			if (settings.bleed && !settings.premultiplyAlpha && !settings.outputFormat.equalsIgnoreCase("jpg")) {
a62d533 201
				canvas = new ColorBleedEffect().processImage(canvas, 2);
a62d533 202
				g = (Graphics2D)canvas.getGraphics();
a62d533 203
			}
a62d533 204
a62d533 205
			if (settings.debug) {
a62d533 206
				g.setColor(Color.magenta);
a62d533 207
				g.drawRect(0, 0, width - 1, height - 1);
a62d533 208
			}
a62d533 209
a62d533 210
			ImageOutputStream ios = null;
a62d533 211
			try {
a62d533 212
				if (settings.outputFormat.equalsIgnoreCase("jpg")) {
a62d533 213
					BufferedImage newImage = new BufferedImage(canvas.getWidth(), canvas.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
a62d533 214
					newImage.getGraphics().drawImage(canvas, 0, 0, null);
a62d533 215
					canvas = newImage;
a62d533 216
a62d533 217
					Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
a62d533 218
					ImageWriter writer = writers.next();
a62d533 219
					ImageWriteParam param = writer.getDefaultWriteParam();
a62d533 220
					param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
a62d533 221
					param.setCompressionQuality(settings.jpegQuality);
a62d533 222
					ios = ImageIO.createImageOutputStream(outputFile);
a62d533 223
					writer.setOutput(ios);
a62d533 224
					writer.write(null, new IIOImage(canvas, null, null), param);
a62d533 225
				} else {
a62d533 226
					if (settings.premultiplyAlpha) canvas.getColorModel().coerceData(canvas.getRaster(), true);
a62d533 227
					ImageIO.write(canvas, "png", outputFile);
a62d533 228
				}
a62d533 229
			} catch (IOException ex) {
a62d533 230
				throw new RuntimeException("Error writing file: " + outputFile, ex);
a62d533 231
			} finally {
a62d533 232
				if (ios != null) {
a62d533 233
					try {
a62d533 234
						ios.close();
a62d533 235
					} catch (Exception ignored) {
a62d533 236
					}
a62d533 237
				}
a62d533 238
			}
a62d533 239
		}
a62d533 240
	}
a62d533 241
a62d533 242
	private static void plot (BufferedImage dst, int x, int y, int argb) {
a62d533 243
		if (0 <= x && x < dst.getWidth() && 0 <= y && y < dst.getHeight()) dst.setRGB(x, y, argb);
a62d533 244
	}
a62d533 245
a62d533 246
	private static void copy (BufferedImage src, int x, int y, int w, int h, BufferedImage dst, int dx, int dy, boolean rotated) {
a62d533 247
		if (rotated) {
a62d533 248
			for (int i = 0; i < w; i++)
a62d533 249
				for (int j = 0; j < h; j++)
a62d533 250
					dst.setRGB(dx + j, dy + w - i - 1, src.getRGB(x + i, y + j));
a62d533 251
		} else {
a62d533 252
			for (int i = 0; i < w; i++)
a62d533 253
				for (int j = 0; j < h; j++)
a62d533 254
					dst.setRGB(dx + i, dy + j, src.getRGB(x + i, y + j));
a62d533 255
		}
a62d533 256
	}
a62d533 257
a62d533 258
	private void writePackFile (File outputDir, Array<Page> pages, String packFileName) throws IOException {
a62d533 259
		File packFile = new File(outputDir, packFileName);
a62d533 260
a62d533 261
		if (packFile.exists()) {
a62d533 262
			// Make sure there aren't duplicate names.
a62d533 263
			TextureAtlasData textureAtlasData = new TextureAtlasData(new FileHandle(packFile), new FileHandle(packFile), false);
a62d533 264
			for (Page page : pages) {
a62d533 265
				for (Rect rect : page.outputRects) {
a62d533 266
					String rectName = Rect.getAtlasName(rect.name, settings.flattenPaths);
a62d533 267
					for (Region region : textureAtlasData.getRegions()) {
a62d533 268
						if (region.name.equals(rectName)) {
a62d533 269
							throw new GdxRuntimeException("A region with the name \"" + rectName + "\" has already been packed: "
a62d533 270
								+ rect.name);
a62d533 271
						}
a62d533 272
					}
a62d533 273
				}
a62d533 274
			}
a62d533 275
		}
a62d533 276
a62d533 277
		FileWriter writer = new FileWriter(packFile, true);
a62d533 278
// if (settings.jsonOutput) {
a62d533 279
// } else {
a62d533 280
		for (Page page : pages) {
a62d533 281
			writer.write("\n" + page.imageName + "\n");
a62d533 282
			writer.write("format: " + settings.format + "\n");
a62d533 283
			writer.write("filter: " + settings.filterMin + "," + settings.filterMag + "\n");
a62d533 284
			writer.write("repeat: " + getRepeatValue() + "\n");
a62d533 285
a62d533 286
			for (Rect rect : page.outputRects) {
a62d533 287
				writeRect(writer, page, rect, rect.name);
a62d533 288
				for (Alias alias : rect.aliases) {
a62d533 289
					Rect aliasRect = new Rect();
a62d533 290
					aliasRect.set(rect);
a62d533 291
					alias.apply(aliasRect);
a62d533 292
					writeRect(writer, page, aliasRect, alias.name);
a62d533 293
				}
a62d533 294
			}
a62d533 295
		}
a62d533 296
// }
a62d533 297
		writer.close();
a62d533 298
	}
a62d533 299
a62d533 300
	private void writeRect (FileWriter writer, Page page, Rect rect, String name) throws IOException {
a62d533 301
		writer.write(Rect.getAtlasName(name, settings.flattenPaths) + "\n");
a62d533 302
		writer.write("  rotate: " + rect.rotated + "\n");
a62d533 303
		writer.write("  xy: " + (page.x + rect.x) + ", " + (page.y + page.height - rect.height - rect.y) + "\n");
a62d533 304
		writer.write("  size: " + rect.image.getWidth() + ", " + rect.image.getHeight() + "\n");
a62d533 305
		if (rect.splits != null) {
a62d533 306
			writer
a62d533 307
				.write("  split: " + rect.splits[0] + ", " + rect.splits[1] + ", " + rect.splits[2] + ", " + rect.splits[3] + "\n");
a62d533 308
		}
a62d533 309
		if (rect.pads != null) {
a62d533 310
			if (rect.splits == null) writer.write("  split: 0, 0, 0, 0\n");
a62d533 311
			writer.write("  pad: " + rect.pads[0] + ", " + rect.pads[1] + ", " + rect.pads[2] + ", " + rect.pads[3] + "\n");
a62d533 312
		}
a62d533 313
		writer.write("  orig: " + rect.originalWidth + ", " + rect.originalHeight + "\n");
a62d533 314
		writer.write("  offset: " + rect.offsetX + ", " + (rect.originalHeight - rect.image.getHeight() - rect.offsetY) + "\n");
a62d533 315
		writer.write("  index: " + rect.index + "\n");
a62d533 316
	}
a62d533 317
a62d533 318
	private String getRepeatValue () {
a62d533 319
		if (settings.wrapX == TextureWrap.Repeat && settings.wrapY == TextureWrap.Repeat) return "xy";
a62d533 320
		if (settings.wrapX == TextureWrap.Repeat && settings.wrapY == TextureWrap.ClampToEdge) return "x";
a62d533 321
		if (settings.wrapX == TextureWrap.ClampToEdge && settings.wrapY == TextureWrap.Repeat) return "y";
a62d533 322
		return "none";
a62d533 323
	}
a62d533 324
a62d533 325
	private int getBufferedImageType (Format format) {
a62d533 326
		switch (settings.format) {
a62d533 327
		case RGBA8888:
a62d533 328
		case RGBA4444:
a62d533 329
			return BufferedImage.TYPE_INT_ARGB;
a62d533 330
		case RGB565:
a62d533 331
		case RGB888:
a62d533 332
			return BufferedImage.TYPE_INT_RGB;
a62d533 333
		case Alpha:
a62d533 334
			return BufferedImage.TYPE_BYTE_GRAY;
a62d533 335
		default:
a62d533 336
			throw new RuntimeException("Unsupported format: " + settings.format);
a62d533 337
		}
a62d533 338
	}
a62d533 339
a62d533 340
	/** @author Nathan Sweet */
a62d533 341
	public static class Page {
a62d533 342
		public String imageName;
a62d533 343
		public Array<Rect> outputRects, remainingRects;
a62d533 344
		public float occupancy;
a62d533 345
		public int x, y, width, height;
a62d533 346
	}
a62d533 347
a62d533 348
	/** @author Regnarock
a62d533 349
	 * @author Nathan Sweet */
a62d533 350
	public static class Alias {
a62d533 351
		public String name;
a62d533 352
		public int index;
a62d533 353
		public int[] splits;
a62d533 354
		public int[] pads;
a62d533 355
		public int offsetX, offsetY, originalWidth, originalHeight;
a62d533 356
a62d533 357
		public Alias (Rect rect) {
a62d533 358
			name = rect.name;
a62d533 359
			index = rect.index;
a62d533 360
			splits = rect.splits;
a62d533 361
			pads = rect.pads;
a62d533 362
			offsetX = rect.offsetX;
a62d533 363
			offsetY = rect.offsetY;
a62d533 364
			originalWidth = rect.originalWidth;
a62d533 365
			originalHeight = rect.originalHeight;
a62d533 366
		}
a62d533 367
a62d533 368
		public void apply (Rect rect) {
a62d533 369
			rect.name = name;
a62d533 370
			rect.index = index;
a62d533 371
			rect.splits = splits;
a62d533 372
			rect.pads = pads;
a62d533 373
			rect.offsetX = offsetX;
a62d533 374
			rect.offsetY = offsetY;
a62d533 375
			rect.originalWidth = originalWidth;
a62d533 376
			rect.originalHeight = originalHeight;
a62d533 377
		}
a62d533 378
	}
a62d533 379
a62d533 380
	/** @author Nathan Sweet */
a62d533 381
	public static class Rect {
a62d533 382
		public String name;
a62d533 383
		public BufferedImage image;
a62d533 384
		public int offsetX, offsetY, originalWidth, originalHeight;
a62d533 385
		public int x, y, width, height;
a62d533 386
		public int index;
a62d533 387
		public boolean rotated;
a62d533 388
		public Set<Alias> aliases = new HashSet<Alias>();
a62d533 389
		public int[] splits;
a62d533 390
		public int[] pads;
a62d533 391
		public boolean canRotate = true;
a62d533 392
a62d533 393
		int score1, score2;
a62d533 394
a62d533 395
		Rect (BufferedImage source, int left, int top, int newWidth, int newHeight) {
a62d533 396
			image = new BufferedImage(source.getColorModel(), source.getRaster().createWritableChild(left, top, newWidth, newHeight,
a62d533 397
				0, 0, null), source.getColorModel().isAlphaPremultiplied(), null);
a62d533 398
			offsetX = left;
a62d533 399
			offsetY = top;
a62d533 400
			originalWidth = source.getWidth();
a62d533 401
			originalHeight = source.getHeight();
a62d533 402
			width = newWidth;
a62d533 403
			height = newHeight;
a62d533 404
		}
a62d533 405
a62d533 406
		Rect () {
a62d533 407
		}
a62d533 408
a62d533 409
		Rect (Rect rect) {
a62d533 410
			setSize(rect);
a62d533 411
		}
a62d533 412
a62d533 413
		void setSize (Rect rect) {
a62d533 414
			x = rect.x;
a62d533 415
			y = rect.y;
a62d533 416
			width = rect.width;
a62d533 417
			height = rect.height;
a62d533 418
		}
a62d533 419
a62d533 420
		void set (Rect rect) {
a62d533 421
			name = rect.name;
a62d533 422
			image = rect.image;
a62d533 423
			offsetX = rect.offsetX;
a62d533 424
			offsetY = rect.offsetY;
a62d533 425
			originalWidth = rect.originalWidth;
a62d533 426
			originalHeight = rect.originalHeight;
a62d533 427
			x = rect.x;
a62d533 428
			y = rect.y;
a62d533 429
			width = rect.width;
a62d533 430
			height = rect.height;
a62d533 431
			index = rect.index;
a62d533 432
			rotated = rect.rotated;
a62d533 433
			aliases = rect.aliases;
a62d533 434
			splits = rect.splits;
a62d533 435
			pads = rect.pads;
a62d533 436
			canRotate = rect.canRotate;
a62d533 437
			score1 = rect.score1;
a62d533 438
			score2 = rect.score2;
a62d533 439
		}
a62d533 440
a62d533 441
		@Override
a62d533 442
		public boolean equals (Object obj) {
a62d533 443
			if (this == obj) return true;
a62d533 444
			if (obj == null) return false;
a62d533 445
			if (getClass() != obj.getClass()) return false;
a62d533 446
			Rect other = (Rect)obj;
a62d533 447
			if (name == null) {
a62d533 448
				if (other.name != null) return false;
a62d533 449
			} else if (!name.equals(other.name)) return false;
a62d533 450
			return true;
a62d533 451
		}
a62d533 452
a62d533 453
		@Override
a62d533 454
		public String toString () {
a62d533 455
			return name + "[" + x + "," + y + " " + width + "x" + height + "]";
a62d533 456
		}
a62d533 457
a62d533 458
		static public String getAtlasName (String name, boolean flattenPaths) {
a62d533 459
			return flattenPaths ? new FileHandle(name).name() : name;
a62d533 460
		}
a62d533 461
	}
a62d533 462
a62d533 463
	/** @author Nathan Sweet */
a62d533 464
	static public class Settings {
a62d533 465
		public boolean pot = true;
a62d533 466
		public int paddingX = 2, paddingY = 2;
a62d533 467
		public boolean edgePadding = true;
a62d533 468
		public boolean duplicatePadding = false;
a62d533 469
		public boolean rotation;
a62d533 470
		public int minWidth = 16, minHeight = 16;
a62d533 471
		public int maxWidth = 1024, maxHeight = 1024;
a62d533 472
		public boolean forceSquareOutput = false;
a62d533 473
		public boolean stripWhitespaceX, stripWhitespaceY;
a62d533 474
		public int alphaThreshold;
a62d533 475
		public TextureFilter filterMin = TextureFilter.Nearest, filterMag = TextureFilter.Nearest;
a62d533 476
		public TextureWrap wrapX = TextureWrap.ClampToEdge, wrapY = TextureWrap.ClampToEdge;
a62d533 477
		public Format format = Format.RGBA8888;
a62d533 478
		public boolean alias = true;
a62d533 479
		public String outputFormat = "png";
a62d533 480
		public float jpegQuality = 0.9f;
a62d533 481
		public boolean ignoreBlankImages = true;
a62d533 482
		public boolean fast;
a62d533 483
		public boolean debug;
a62d533 484
		public boolean combineSubdirectories;
a62d533 485
		public boolean flattenPaths;
a62d533 486
		public boolean premultiplyAlpha;
a62d533 487
		public boolean useIndexes = true;
a62d533 488
		public boolean bleed = true;
a62d533 489
a62d533 490
		public Settings () {
a62d533 491
		}
a62d533 492
a62d533 493
		public Settings (Settings settings) {
a62d533 494
			fast = settings.fast;
a62d533 495
			rotation = settings.rotation;
a62d533 496
			pot = settings.pot;
a62d533 497
			minWidth = settings.minWidth;
a62d533 498
			minHeight = settings.minHeight;
a62d533 499
			maxWidth = settings.maxWidth;
a62d533 500
			maxHeight = settings.maxHeight;
a62d533 501
			paddingX = settings.paddingX;
a62d533 502
			paddingY = settings.paddingY;
a62d533 503
			edgePadding = settings.edgePadding;
a62d533 504
			duplicatePadding = settings.duplicatePadding;
a62d533 505
			alphaThreshold = settings.alphaThreshold;
a62d533 506
			ignoreBlankImages = settings.ignoreBlankImages;
a62d533 507
			stripWhitespaceX = settings.stripWhitespaceX;
a62d533 508
			stripWhitespaceY = settings.stripWhitespaceY;
a62d533 509
			alias = settings.alias;
a62d533 510
			format = settings.format;
a62d533 511
			jpegQuality = settings.jpegQuality;
a62d533 512
			outputFormat = settings.outputFormat;
a62d533 513
			filterMin = settings.filterMin;
a62d533 514
			filterMag = settings.filterMag;
a62d533 515
			wrapX = settings.wrapX;
a62d533 516
			wrapY = settings.wrapY;
a62d533 517
			debug = settings.debug;
a62d533 518
			combineSubdirectories = settings.combineSubdirectories;
a62d533 519
			flattenPaths = settings.flattenPaths;
a62d533 520
			premultiplyAlpha = settings.premultiplyAlpha;
a62d533 521
			forceSquareOutput = settings.forceSquareOutput;
a62d533 522
			useIndexes = settings.useIndexes;
a62d533 523
			bleed = settings.bleed;
a62d533 524
		}
a62d533 525
	}
a62d533 526
a62d533 527
	static public void process (String input, String output, String packFileName) {
a62d533 528
		try {
a62d533 529
			new TexturePackerFileProcessor(new Settings(), packFileName).process(new File(input), new File(output));
a62d533 530
		} catch (Exception ex) {
a62d533 531
			throw new RuntimeException("Error packing files.", ex);
a62d533 532
		}
a62d533 533
	}
a62d533 534
a62d533 535
	static public void process (Settings settings, String input, String output, String packFileName) {
a62d533 536
		try {
a62d533 537
			new TexturePackerFileProcessor(settings, packFileName).process(new File(input), new File(output));
a62d533 538
		} catch (Exception ex) {
a62d533 539
			throw new RuntimeException("Error packing files.", ex);
a62d533 540
		}
a62d533 541
	}
a62d533 542
a62d533 543
	/** @return true if the output file does not yet exist or its last modification date is before the last modification date of the
a62d533 544
	 *         input file */
a62d533 545
	static public boolean isModified (String input, String output, String packFileName) {
a62d533 546
		String packFullFileName = output;
a62d533 547
		if (!packFullFileName.endsWith("/")) packFullFileName += "/";
a62d533 548
		packFullFileName += packFileName;
a62d533 549
		File outputFile = new File(packFullFileName);
a62d533 550
		if (!outputFile.exists()) return true;
a62d533 551
a62d533 552
		File inputFile = new File(input);
a62d533 553
		if (!inputFile.exists()) throw new IllegalArgumentException("Input file does not exist: " + inputFile.getAbsolutePath());
a62d533 554
		return inputFile.lastModified() > outputFile.lastModified();
a62d533 555
	}
a62d533 556
a62d533 557
	static public void processIfModified (String input, String output, String packFileName) {
a62d533 558
		if (isModified(input, output, packFileName)) process(input, output, packFileName);
a62d533 559
	}
a62d533 560
a62d533 561
	static public void processIfModified (Settings settings, String input, String output, String packFileName) {
a62d533 562
		if (isModified(input, output, packFileName)) process(settings, input, output, packFileName);
a62d533 563
	}
a62d533 564
}