All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.badlogic.gdx.tools.texturepacker.TexturePackerFileProcessor Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * 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.texturepacker;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.badlogic.gdx.tools.FileProcessor;
import com.badlogic.gdx.tools.texturepacker.TexturePacker.ProgressListener;
import com.badlogic.gdx.tools.texturepacker.TexturePacker.Settings;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.Json;
import com.badlogic.gdx.utils.JsonReader;
import com.badlogic.gdx.utils.JsonValue;
import com.badlogic.gdx.utils.ObjectMap;

/** @author Nathan Sweet */
public class TexturePackerFileProcessor extends FileProcessor {
	private final Settings defaultSettings;
	private final ProgressListener progress;
	private ObjectMap dirToSettings = new ObjectMap();
	private Json json = new Json();
	private String packFileName;
	private File root;
	ArrayList ignoreDirs = new ArrayList();
	boolean countOnly;
	int packCount;

	public TexturePackerFileProcessor () {
		this(new Settings(), "pack.atlas", null);
	}

	/** @param progress May be null. */
	public TexturePackerFileProcessor (Settings defaultSettings, String packFileName, ProgressListener progress) {
		this.defaultSettings = defaultSettings;
		this.progress = progress;

		if (packFileName.toLowerCase().endsWith(defaultSettings.atlasExtension.toLowerCase()))
			packFileName = packFileName.substring(0, packFileName.length() - defaultSettings.atlasExtension.length());
		this.packFileName = packFileName;

		setFlattenOutput(true);
		addInputSuffix(".png", ".jpg", ".jpeg");

		// Sort input files by name to avoid platform-dependent atlas output changes.
		setComparator(new Comparator() {
			public int compare (File file1, File file2) {
				return file1.getName().compareTo(file2.getName());
			}
		});
	}

	public ArrayList process (File inputFile, File outputRoot) throws Exception {
		root = inputFile;

		// Collect pack.json setting files.
		final ArrayList settingsFiles = new ArrayList();
		FileProcessor settingsProcessor = new FileProcessor() {
			protected void processFile (Entry inputFile) throws Exception {
				settingsFiles.add(inputFile.inputFile);
			}
		};
		settingsProcessor.addInputRegex("pack\\.json");
		settingsProcessor.process(inputFile, null);
		// Sort parent first.
		Collections.sort(settingsFiles, new Comparator() {
			public int compare (File file1, File file2) {
				return file1.toString().length() - file2.toString().length();
			}
		});
		for (File settingsFile : settingsFiles) {
			// Find first parent with settings, or use defaults.
			Settings settings = null;
			File parent = settingsFile.getParentFile();
			while (true) {
				if (parent.equals(root)) break;
				parent = parent.getParentFile();
				settings = dirToSettings.get(parent);
				if (settings != null) {
					settings = newSettings(settings);
					break;
				}
			}
			if (settings == null) settings = newSettings(defaultSettings);
			// Merge settings from current directory.
			merge(settings, settingsFile);
			dirToSettings.put(settingsFile.getParentFile(), settings);
		}

		// Count the number of texture packer invocations.
		countOnly = true;
		super.process(inputFile, outputRoot);
		countOnly = false;

		// Do actual processing.
		if (progress != null) progress.start(1);
		ArrayList result = super.process(inputFile, outputRoot);
		if (progress != null) progress.end();
		return result;
	}

	void merge (Settings settings, File settingsFile) {
		try {
			JsonValue root = new JsonReader().parse(new FileReader(settingsFile));
			if (root == null) return; // Empty file.
			json.readFields(settings, root);
		} catch (Exception ex) {
			throw new GdxRuntimeException("Error reading settings file: " + settingsFile, ex);
		}
	}

	public ArrayList process (File[] files, File outputRoot) throws Exception {
		// Delete pack file and images.
		if (countOnly && outputRoot.exists()) deleteOutput(outputRoot);
		return super.process(files, outputRoot);
	}

	protected void deleteOutput (File outputRoot) throws Exception {
		// Load root settings to get scale.
		File settingsFile = new File(root, "pack.json");
		Settings rootSettings = defaultSettings;
		if (settingsFile.exists()) {
			rootSettings = newSettings(rootSettings);
			merge(rootSettings, settingsFile);
		}

		String atlasExtension = rootSettings.atlasExtension == null ? "" : rootSettings.atlasExtension;
		atlasExtension = Pattern.quote(atlasExtension);

		for (int i = 0, n = rootSettings.scale.length; i < n; i++) {
			FileProcessor deleteProcessor = new FileProcessor() {
				protected void processFile (Entry inputFile) throws Exception {
					inputFile.inputFile.delete();
				}
			};
			deleteProcessor.setRecursive(false);

			File packFile = new File(rootSettings.getScaledPackFileName(packFileName, i));
			String scaledPackFileName = packFile.getName();

			String prefix = packFile.getName();
			int dotIndex = prefix.lastIndexOf('.');
			if (dotIndex != -1) prefix = prefix.substring(0, dotIndex);
			deleteProcessor.addInputRegex("(?i)" + prefix + "-?\\d*\\.(png|jpg|jpeg)");
			deleteProcessor.addInputRegex("(?i)" + prefix + atlasExtension);

			String dir = packFile.getParent();
			if (dir == null)
				deleteProcessor.process(outputRoot, null);
			else if (new File(outputRoot + "/" + dir).exists()) //
				deleteProcessor.process(outputRoot + "/" + dir, null);
		}
	}

	protected void processDir (final Entry inputDir, ArrayList files) throws Exception {
		if (ignoreDirs.contains(inputDir.inputFile)) return;

		// Find first parent with settings, or use defaults.
		Settings settings = null;
		File parent = inputDir.inputFile;
		while (true) {
			settings = dirToSettings.get(parent);
			if (settings != null) break;
			if (parent == null || parent.equals(root)) break;
			parent = parent.getParentFile();
		}
		if (settings == null) settings = defaultSettings;

		if (settings.ignore) return;

		if (settings.combineSubdirectories) {
			// Collect all files under subdirectories except those with a pack.json file. A directory with its own settings can't be
			// combined since combined directories must use the settings of the parent directory.
			files = new FileProcessor(this) {
				protected void processDir (Entry entryDir, ArrayList files) {
					File file = entryDir.inputFile;
					while (file != null && !file.equals(inputDir.inputFile)) {
						if (new File(file, "pack.json").exists()) {
							files.clear();
							return;
						}
						file = file.getParentFile();
					}
					if (!countOnly) ignoreDirs.add(entryDir.inputFile);
				}

				protected void processFile (Entry entry) {
					addProcessedFile(entry);
				}
			}.process(inputDir.inputFile, null);
		}

		if (files.isEmpty()) return;

		if (countOnly) {
			packCount++;
			return;
		}

		// Sort by name using numeric suffix, then alpha.
		Collections.sort(files, new Comparator() {
			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.
		if (!settings.silent) {
			try {
				System.out.println("Reading: " + inputDir.inputFile.getCanonicalPath());
			} catch (IOException ignored) {
				System.out.println("Reading: " + inputDir.inputFile.getAbsolutePath());
			}
		}
		if (progress != null) {
			progress.start(1f / packCount);
			String inputPath = null;
			try {
				String rootPath = root.getCanonicalPath();
				inputPath = inputDir.inputFile.getCanonicalPath();
				if (inputPath.startsWith(rootPath)) {
					rootPath = rootPath.replace('\\', '/');
					inputPath = inputPath.substring(rootPath.length()).replace('\\', '/');
					if (inputPath.startsWith("/")) inputPath = inputPath.substring(1);
				}
			} catch (IOException ignored) {
			}
			if (inputPath == null || inputPath.length() == 0) inputPath = inputDir.inputFile.getName();
			progress.setMessage(inputPath);
		}
		TexturePacker packer = newTexturePacker(root, settings);
		for (Entry file : files)
			packer.addImage(file.inputFile);
		pack(packer, inputDir);
		if (progress != null) progress.end();
	}

	protected void pack (TexturePacker packer, Entry inputDir) {
		packer.pack(inputDir.outputDir, packFileName);
	}

	protected TexturePacker newTexturePacker (File root, Settings settings) {
		TexturePacker packer = new TexturePacker(root, settings);
		packer.setProgressListener(progress);
		return packer;
	}

	protected Settings newSettings (Settings settings) {
		return new Settings(settings);
	}

	public ProgressListener getProgressListener () {
		return progress;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy