[editor only] Sprite Sheet to Animation splitter

This commit is contained in:
fgnm
2022-05-24 19:28:12 +02:00
parent 1a890bc757
commit a9fc469b2e
6 changed files with 217 additions and 1 deletions
+2
View File
@@ -5,6 +5,8 @@
- Fixed import Spine animations exported in compatibility mode
- Add support to path as atlas region name
- Hide `white-pixel` resource because mandatory
- Check updates for Snapshot builds
- Sprite Sheet to Animation splitter
**Runtime**
- [BREAK CHANGE] Improve `ActionEventListener` with `entity` parameter
@@ -89,6 +89,7 @@ public class BootstrapViewCommand extends SimpleCommand {
facade.registerMediator(new NodeEditorDialogMediator());
facade.registerMediator(new CreatePlaceholderDialogMediator());
facade.registerMediator(new CreateNoiseDialogMediator());
facade.registerMediator(new ImportSpriteSheetDialogMediator());
facade.registerMediator(new ConsoleDialogMediator());
facade.registerMediator(new ImagesPackDialogMediator());
facade.registerMediator(new AnimationsPackDialogMediator());
@@ -12,6 +12,7 @@ import static games.rednblack.h2d.common.MenuAPI.RESOURCE_MENU;
public class ResourcesMenu extends H2DMenu {
public static final String IMPORT_TO_LIBRARY = HyperLap2DMenuBar.prefix + ".IMPORT_TO_LIBRARY";
public static final String IMPORT_SPRITE_SHEET = HyperLap2DMenuBar.prefix + ".IMPORT_SPRITE_SHEET";
public static final String CREATE_PLACEHOLDER = HyperLap2DMenuBar.prefix + ".CREATE_PLACEHOLDER";
public static final String CREATE_NOISE = HyperLap2DMenuBar.prefix + ".CREATE_NOISE";
public static final String OPEN_IMAGES_PACK = HyperLap2DMenuBar.prefix + ".OPEN_IMAGES_PACK";
@@ -21,6 +22,7 @@ public class ResourcesMenu extends H2DMenu {
public ResourcesMenu() {
super("Resources");
MenuItem importToLibrary = new MenuItem("Import Resources...", new MenuItemListener(IMPORT_TO_LIBRARY, null, FILE_MENU)).setShortcut(KeyBindingsLayout.getShortcutList(KeyBindingsLayout.IMPORT_TO_LIBRARY));
MenuItem importSpriteSheet = new MenuItem("Import Sprite Sheet Animation...", new MenuItemListener(IMPORT_SPRITE_SHEET, null, RESOURCE_MENU));
MenuItem placeholders = new MenuItem("Create Placeholder...", new MenuItemListener(CREATE_PLACEHOLDER, null, RESOURCE_MENU));
MenuItem noise = new MenuItem("Create Perlin Noise...", new MenuItemListener(CREATE_NOISE, null, RESOURCE_MENU));
MenuItem repack = new MenuItem("Repack Assets", new MenuItemListener(MsgAPI.ACTION_REPACK, null, RESOURCE_MENU));
@@ -38,6 +40,7 @@ public class ResourcesMenu extends H2DMenu {
addSeparator();
addItem(placeholders);
addItem(noise);
addItem(importSpriteSheet);
}
@Override
@@ -49,7 +49,7 @@ public class ConsoleDialog extends H2DDialog {
private Color lastBackgroundColor = Color.CLEAR;
private H2DHighlight.TextFormat lastTextFormat = H2DHighlight.TextFormat.NORMAL;
public static int MAX_TEXT_LENGTH = 5000;
public static int MAX_TEXT_LENGTH = 10000;
public ConsoleDialog() {
super("Console", "console");
@@ -0,0 +1,85 @@
package games.rednblack.editor.view.ui.dialog;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.kotcrab.vis.ui.util.Validators;
import com.kotcrab.vis.ui.widget.VisLabel;
import com.kotcrab.vis.ui.widget.VisTable;
import com.kotcrab.vis.ui.widget.VisTextButton;
import com.kotcrab.vis.ui.widget.VisValidatableTextField;
import com.kotcrab.vis.ui.widget.file.FileChooser;
import games.rednblack.editor.HyperLap2DFacade;
import games.rednblack.h2d.common.H2DDialog;
import games.rednblack.h2d.common.view.ui.StandardWidgetsFactory;
import games.rednblack.h2d.common.view.ui.widget.InputFileWidget;
import org.puremvc.java.interfaces.IFacade;
public class ImportSpriteSheetDialog extends H2DDialog {
private static final String prefix = "games.rednblack.editor.view.ui.dialog.ImportSpriteSheetDialog";
public static final String IMPORT_SPRITE_SHEET = prefix + ".IMPORT_SPRITE_SHEET";
private final VisValidatableTextField width, height;
private final InputFileWidget imagePathField;
private final VisTextButton importButton;
private final IFacade facade;
public ImportSpriteSheetDialog() {
super("Import Sprite Sheet Animation");
addCloseButton();
this.facade = HyperLap2DFacade.getInstance();
setModal(true);
VisTable fileTable = new VisTable();
fileTable.pad(6);
//
fileTable.add(new VisLabel("Sprite Sheet:")).right().padRight(5);
imagePathField = new InputFileWidget(FileChooser.Mode.OPEN, FileChooser.SelectionMode.FILES, false);
imagePathField.setTextFieldWidth(156);
fileTable.add(imagePathField);
getContentTable().add(fileTable);
//
getContentTable().row().padTop(10);
//
Validators.IntegerValidator validator = new Validators.IntegerValidator();
width = StandardWidgetsFactory.createValidableTextField(validator);
height = StandardWidgetsFactory.createValidableTextField(validator);
VisTable sizeTable = new VisTable();
sizeTable.add("Sprite Width:").padRight(3);
sizeTable.add(width).width(60);
sizeTable.add("px").padLeft(5);
sizeTable.row().padTop(5);
sizeTable.add("Sprite Height:").padRight(3);
sizeTable.add(height).width(60);
sizeTable.add("px").padLeft(5);
getContentTable().add(sizeTable);
importButton = StandardWidgetsFactory.createTextButton("Import");
getButtonsTable().add(importButton);
pack();
setListeners();
}
public int getSpriteWidth() {
return Integer.parseInt(width.getText());
}
public int getSpriteHeight() {
return Integer.parseInt(height.getText());
}
private void setListeners() {
importButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if (width.isInputValid() && height.isInputValid() && imagePathField.getValue() != null) {
facade.sendNotification(IMPORT_SPRITE_SHEET, imagePathField.getValue());
}
}
});
}
}
@@ -0,0 +1,125 @@
package games.rednblack.editor.view.ui.dialog;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.PixmapIO;
import com.badlogic.gdx.tools.texturepacker.TexturePacker;
import games.rednblack.editor.HyperLap2DFacade;
import games.rednblack.editor.proxy.ProjectManager;
import games.rednblack.editor.view.menu.ResourcesMenu;
import games.rednblack.editor.view.stage.Sandbox;
import games.rednblack.editor.view.stage.UIStage;
import games.rednblack.h2d.common.MsgAPI;
import org.apache.commons.io.FileUtils;
import org.puremvc.java.interfaces.INotification;
import org.puremvc.java.patterns.mediator.Mediator;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ImportSpriteSheetDialogMediator extends Mediator<ImportSpriteSheetDialog> {
private static final String TAG = ImportSpriteSheetDialogMediator.class.getCanonicalName();
private static final String NAME = TAG;
public ImportSpriteSheetDialogMediator() {
super(NAME, new ImportSpriteSheetDialog());
}
@Override
public void onRegister() {
super.onRegister();
facade = HyperLap2DFacade.getInstance();
}
@Override
public String[] listNotificationInterests() {
return new String[]{
ResourcesMenu.IMPORT_SPRITE_SHEET,
ImportSpriteSheetDialog.IMPORT_SPRITE_SHEET
};
}
@Override
public void handleNotification(INotification notification) {
super.handleNotification(notification);
Sandbox sandbox = Sandbox.getInstance();
UIStage uiStage = sandbox.getUIStage();
switch (notification.getName()) {
case ResourcesMenu.IMPORT_SPRITE_SHEET:
viewComponent.show(uiStage);
break;
case ImportSpriteSheetDialog.IMPORT_SPRITE_SHEET:
FileHandle spriteSheet = notification.getBody();
importSpriteSheet(spriteSheet);
break;
}
}
private void importSpriteSheet(FileHandle spriteSheet) {
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(() -> {
facade.sendNotification(MsgAPI.SHOW_LOADING_DIALOG);
byte[] image = spriteSheet.readBytes();
Pixmap pixmap = new Pixmap(image, 0, image.length);
String name = spriteSheet.nameWithoutExtension();
int spriteW = viewComponent.getSpriteWidth();
int spriteH = viewComponent.getSpriteHeight();
ProjectManager projectManager = facade.retrieveProxy(ProjectManager.NAME);
projectManager.getCurrentProjectInfoVO().animationsPacks.get("main").regions.add(name);
String targetPath = projectManager.getCurrentProjectPath() + File.separator
+ ProjectManager.SPRITE_DIR_PATH + File.separator + name;
File targetDir = new File(targetPath);
try {
FileUtils.forceMkdir(targetDir);
} catch (IOException e) {
e.printStackTrace();
facade.sendNotification(MsgAPI.HIDE_LOADING_DIALOG);
return;
}
TexturePacker.Settings settings = projectManager.getTexturePackerSettings();
TexturePacker tp = new TexturePacker(settings);
int i = 0;
for (int x = 0; x < pixmap.getWidth(); x += spriteW) {
for (int y = 0; y < pixmap.getHeight(); y += spriteH) {
int w = x + spriteW <= pixmap.getWidth() ? spriteW : pixmap.getWidth() - x;
int h = y + spriteH <= pixmap.getHeight() ? spriteH : pixmap.getHeight() - y;
Pixmap tilePixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
tilePixmap.drawPixmap(pixmap, 0, 0, x, y, w, h);
String imagesPath = projectManager.getCurrentRawImagesPath() + File.separator + name + "_" + i + ".png";
FileHandle path = new FileHandle(imagesPath);
PixmapIO.writePNG(path, tilePixmap);
tilePixmap.dispose();
tp.addImage(path.file());
i++;
}
}
pixmap.dispose();
tp.pack(targetDir, name);
viewComponent.close();
facade.sendNotification(MsgAPI.HIDE_LOADING_DIALOG);
Gdx.app.postRunnable(() -> {
facade.sendNotification(MsgAPI.UPDATE_ATLAS_PACK_LIST);
facade.sendNotification(MsgAPI.ACTION_REPACK);
});
});
executor.shutdown();
}
}