From 850ad90403ed96156ae846a00690b20b8f18eede Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Thu, 4 Mar 2021 17:37:04 +0100 Subject: [PATCH 01/54] Add gson dependency Version: gson 2.8.6 --- build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.gradle b/build.gradle index a4f372293..ae1cdfe81 100644 --- a/build.gradle +++ b/build.gradle @@ -49,6 +49,8 @@ dependencies { implementation 'com.sun.xml.bind:jaxb-core:2.3.0.1' implementation 'com.sun.xml.bind:jaxb-impl:2.3.2' + implementation 'com.google.code.gson:gson:2.8.6' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0' testImplementation 'org.junit.jupiter:junit-jupiter-params:5.6.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0' From 7a0f8f5dbc48b93f08fbf27baf897541a6507146 Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Thu, 4 Mar 2021 17:59:30 +0100 Subject: [PATCH 02/54] Add new file AsepriteHandler.java This file is intended to handle importing and exporting of Aseprite JSON files for animations. --- .../litiengine/graphics/animation/AsepriteHandler.java | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java new file mode 100644 index 000000000..fe52971f5 --- /dev/null +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -0,0 +1,5 @@ +package de.gurkenlabs.litiengine.graphics.animation; + +public class AsepriteHandler { + +} From 083e2c4435b205e7f0c34440248664d9fa5e2c9f Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 11:25:12 +0100 Subject: [PATCH 03/54] Fix access modifiers in Animation to support exporting Json This changes the access modifiers of the fields keyframes, name and spritesheet in Animation-class so it can be used in the export process. --- .../gurkenlabs/litiengine/graphics/animation/Animation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java b/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java index f08983f55..f945b4d96 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java @@ -27,9 +27,9 @@ public class Animation implements IUpdateable, ILaunchable { public static final int DEFAULT_FRAME_DURATION = 120; private static final Logger log = Logger.getLogger(Animation.class.getName()); - private final List keyframes; - private final String name; - private Spritesheet spritesheet; + public final List keyframes; + public final String name; + public Spritesheet spritesheet; private KeyFrame currentFrame; private long lastFrameUpdate; From 5fc9246e432902ff22b9ef547deaf9019cf2e477 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 11:27:23 +0100 Subject: [PATCH 04/54] Add object structure for aseprite json This adds the basic structure of Json format aseprite uses. --- .../graphics/animation/AsepriteHandler.java | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index fe52971f5..1d0fb4a2c 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -1,5 +1,82 @@ package de.gurkenlabs.litiengine.graphics.animation; +import java.awt.Image; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; +import java.util.HashMap; +import java.util.Map; + +import de.gurkenlabs.litiengine.graphics.animation.Animation; +import de.gurkenlabs.litiengine.graphics.animation.KeyFrame; +import de.gurkenlabs.litiengine.graphics.Spritesheet; + public class AsepriteHandler { + private class Frames { + transient String name; + Map frame; + boolean rotated; + boolean trimmed; + Map spriteSourceSize; + Map sourceSize; + int duration; + + public Frames(String name, Map frame, boolean rotated, boolean trimmed, Map spriteSourceSize, Map sourceSize, int duration){ + this.name = name; + this.frame = frame; + this.rotated = rotated; + this.trimmed = trimmed; + this.spriteSourceSize = spriteSourceSize; + this.sourceSize = sourceSize; + this.duration = duration; + } + + + } + + private class Meta { + String app; + String version; + String image; + String format; + Map size; + String scale; + Layer[] layers; + + + + public Meta(String app, String version, String image, String format, Map size, String scale, Layer[] layers){ + this.app = app; + this.version = version; + this.image = image; + this.format = format; + this.size = size; + this. scale = scale; + this.layers = layers; + + } + + } + + private class Layer { + String name; + int opacity; + String blendMode; + + public Layer(String name, int opacity, String blendMode){ + this.name = name; + this.opacity = opacity; + this.blendMode = blendMode; + } + + } + + + + + } + + From 7f0624381a25fd93bf0d6bcc8f3d39a5aebafca0 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 12:00:41 +0100 Subject: [PATCH 05/54] Revert "Fix access modifiers in Animation to support exporting Json" This reverts commit 083e2c4435b205e7f0c34440248664d9fa5e2c9f. --- .../gurkenlabs/litiengine/graphics/animation/Animation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java b/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java index f945b4d96..f08983f55 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/Animation.java @@ -27,9 +27,9 @@ public class Animation implements IUpdateable, ILaunchable { public static final int DEFAULT_FRAME_DURATION = 120; private static final Logger log = Logger.getLogger(Animation.class.getName()); - public final List keyframes; - public final String name; - public Spritesheet spritesheet; + private final List keyframes; + private final String name; + private Spritesheet spritesheet; private KeyFrame currentFrame; private long lastFrameUpdate; From 7e53123f364bb22931707ff76b56a378c1f7b284 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 12:24:24 +0100 Subject: [PATCH 06/54] Add functionality to create json with frames object This adds a function that creates the aseprite json as a string representation. it currently only works for the frames object and does not include the meta-data object. --- .../graphics/animation/AsepriteHandler.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 1d0fb4a2c..86aff8671 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -5,8 +5,10 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.annotations.SerializedName; + import java.util.HashMap; import java.util.Map; +import java.util.List; import de.gurkenlabs.litiengine.graphics.animation.Animation; import de.gurkenlabs.litiengine.graphics.animation.KeyFrame; @@ -14,6 +16,74 @@ public class AsepriteHandler { + + public void exportAnimation(Animation animation){ + + String json = createJson(animation); + System.out.println("JSON: " + json); + } + + private String createJson(Animation animation){ + Spritesheet spritesheet = animation.getSpritesheet(); + List keyframes = animation.getKeyframes(); + Frames[] frames = new Frames[keyframes.size()]; + + if(frames.length != spritesheet.getTotalNumberOfSprites()){ + //ERROR + System.out.println("ERROR"); + } + + int numCol = spritesheet.getColumns(); + int numRows = spritesheet.getRows(); + int frameWidth = spritesheet.getSpriteWidth(); + int frameHeight = spritesheet.getSpriteHeight(); + + for(int i = 0; i < numRows; i++){ + for(int j = 0; j < numCol; j++){ + final int row = i; + final int col = j; + Map frame = new HashMap<>(){{ + put("x", (0 + col*frameWidth) ); + put("y", (0 + row*frameHeight) ); + put("w", frameWidth); + put("h", frameHeight); + }}; + Map spriteSourceSize = new HashMap<>(){{ + put("x", 0); + put("y", 0); + put("w", frameWidth); + put("h", frameHeight); + }}; + Map sourceSize = new HashMap<>(){{ + put("w", frameWidth); + put("h", frameHeight); + }}; + int duration = keyframes.get(i+j).getDuration(); + frames[i+j] = new Frames("frame " + i*j, + frame, + false, + false, + spriteSourceSize, + sourceSize, + duration); + } + } + + + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + StringBuilder sb = new StringBuilder(); + sb.append("{ \"frames\": {\n"); + for(int i = 0; i < frames.length; i++){ + String json = gson.toJson(frames[i]); + sb.append(" \"" + frames[i].name + "\": ").append(json).append(",\n"); + } + sb.append(" },\n"); + //System.out.println("JSON:\n" + sb.toString()); + + return sb.toString(); + } + private class Frames { transient String name; Map frame; From 77b10c417ca0d9de78cb9e1add020b657c92f7e3 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 14:01:01 +0100 Subject: [PATCH 07/54] Fix index of json frames This fixes the broken index when creating the frame objects in aseprite json. --- .../litiengine/graphics/animation/AsepriteHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 86aff8671..0e33545b8 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -59,7 +59,8 @@ private String createJson(Animation animation){ put("h", frameHeight); }}; int duration = keyframes.get(i+j).getDuration(); - frames[i+j] = new Frames("frame " + i*j, + String index = String.valueOf(i+j); + frames[i+j] = new Frames("frame " + index, frame, false, false, From d872f4a227c2c31dc16fe0ca6d96d74bfd179d4b Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 14:01:19 +0100 Subject: [PATCH 08/54] Add spritesheet for testing --- .../aseprite_test_animation/Sprite-0001-sheet.png | Bin 0 -> 246 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animation/Sprite-0001-sheet.png diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animation/Sprite-0001-sheet.png b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animation/Sprite-0001-sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..44a7c127f9c5aed232b18eeecdd6217ac91ba2e4 GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^2|%pC!3HGX9;gigQhPmJ978f1-`+UL+ibwonz%wj z!`Q%&Eosh~18xsnq5@exHf+rN|GvXx!yh5}7gh`mejS=Ao#j9N-Cn&{#zTQ2nI)lz zp+~U6kjcOeXq?2$?fgkxl~T{wKM&7*tL^#O{!-XRal=-fSdX{!q)ctP+!%DTmo$Hn zc#{z8aI(tP+jq5O`ux{>dk-cVPBM;8{&#&|N`9}sN@eWc*lPbW|JEZ{W4~A2;oNg_ t<+3d-4=dkQ1znvnfBtTuRR`)L7y=JxPf9wqTpY+{@O1TaS?83{1ORfuVI2Sf literal 0 HcmV?d00001 From d071aef5b80ed691e4ea4b0a48963cdffedd7b60 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 14:02:02 +0100 Subject: [PATCH 09/54] Add tests for exportAnimation This adds a test for exportAnimation. It prints the constructed json to screen so it can be visualy asserted that it looks like it is supposed too. --- .../animation/AsepriteHandlerTests.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java new file mode 100644 index 000000000..c6aac0e7b --- /dev/null +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -0,0 +1,28 @@ +package de.gurkenlabs.litiengine.graphics.animation; + +import java.io.FileNotFoundException; +import java.awt.image.BufferedImage; + +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import de.gurkenlabs.litiengine.graphics.Spritesheet; +import de.gurkenlabs.litiengine.graphics.animation.Animation; + +public class AsepriteHandlerTests { + + + @Test + public void exportAnimationTest() { + String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animation/Sprite-0001.json"; + BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); + Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); + Animation animation = new Animation(spritesheet, false, false, 2,2,2); + + AsepriteHandler aseprite = new AsepriteHandler(); + aseprite.exportAnimation(animation); + + } +} \ No newline at end of file From c746954e7057e47333b3c09eabb985173f5052f7 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 16:53:47 +0100 Subject: [PATCH 10/54] Add meta object to json in animationExport This adds so that the meta object is created in the json. The app, version, format, scale and layers are now hardcoded. --- .../graphics/animation/AsepriteHandler.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 0e33545b8..7c0aee632 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -33,6 +33,7 @@ private String createJson(Animation animation){ System.out.println("ERROR"); } + // Build the frames object in the json int numCol = spritesheet.getColumns(); int numRows = spritesheet.getRows(); int frameWidth = spritesheet.getSpriteWidth(); @@ -71,6 +72,23 @@ private String createJson(Animation animation){ } + + + // Build the meta object in the json + int spritesheetWidth = frameWidth * numCol; + int spritesheetHeight = frameHeight * numRows; + Map size= new HashMap<>(){{ + put("w", spritesheetWidth); + put("h", spritesheetHeight); + }}; + String spritesheetName = spritesheet.getName(); + Layer[] layers = {new Layer("Layer",255,"normal")}; + Meta meta = new Meta("http://www.aseprite.org/", + "1.2.16.3-x64", + spritesheetName, + "RGBA8888", size, "1", layers); + + // Create the json as string Gson gson = new GsonBuilder().setPrettyPrinting().create(); StringBuilder sb = new StringBuilder(); @@ -80,7 +98,8 @@ private String createJson(Animation animation){ sb.append(" \"" + frames[i].name + "\": ").append(json).append(",\n"); } sb.append(" },\n"); - //System.out.println("JSON:\n" + sb.toString()); + String json = gson.toJson(meta); + sb.append("\"meta\":").append(json); return sb.toString(); } From 172127415325d80f574c95f72db5ab68ec0f7321 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 17:25:06 +0100 Subject: [PATCH 11/54] Add closing bracket to aseprite json --- .../litiengine/graphics/animation/AsepriteHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 7c0aee632..dd2f71aa5 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -99,7 +99,7 @@ private String createJson(Animation animation){ } sb.append(" },\n"); String json = gson.toJson(meta); - sb.append("\"meta\":").append(json); + sb.append("\"meta\":").append(json).append("\n}"); return sb.toString(); } From 0a638d86deff48f967c37d9ac3a84f4b1266dc70 Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 17:25:23 +0100 Subject: [PATCH 12/54] Fix absolute path to spritesheet --- .../litiengine/graphics/animation/AsepriteHandlerTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index c6aac0e7b..ab145cc26 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -16,7 +16,7 @@ public class AsepriteHandlerTests { @Test public void exportAnimationTest() { - String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animation/Sprite-0001.json"; + String spritesheetPath = "C:/Users/Nikla/Documents/Programmering/SoftwareFundamentals/Assignment-3-EC/litiengine/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animation/Sprite-0001-sheet.png"; BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); Animation animation = new Animation(spritesheet, false, false, 2,2,2); From 8b8a49308f866c4f805c80266318e9b9fe7180ed Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Mon, 8 Mar 2021 20:19:04 +0100 Subject: [PATCH 13/54] Add import functionality for Aseprite animations Added function AsepriteHandler.importAnimation takes a path to the Aseprite .json file and returns an internal Animation object. --- .../graphics/animation/AsepriteHandler.java | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index fe52971f5..a8f52731e 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -1,5 +1,191 @@ package de.gurkenlabs.litiengine.graphics.animation; +import java.io.File; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.awt.Dimension; +import java.awt.image.BufferedImage; +import java.util.Set; +import java.util.Map; +import javax.imageio.ImageIO; + +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.JsonObject; + +import de.gurkenlabs.litiengine.graphics.Spritesheet; +import de.gurkenlabs.litiengine.graphics.animation.Animation; + +/** + * Offers an interface to import Aseprite JSON export format. + * Note: requires animation key frames to have same dimensions to support internal animation format. + * */ public class AsepriteHandler { + /** + * Thrown to indicate error when importing Aseprite JSON format. + * */ + public static class ImportAnimationException extends Error { + public ImportAnimationException(String message) { + super(message); + } + } + + /** + * Imports an Aseprite animation (.json + sprite sheet). + * Note: searches for sprite sheet path through .json metadata, specifically 'image' element. This should be an absolute path in system. + * + * @param jsonPath path (including filename) to Aseprite JSON. + * + * @return Animation object represented by each key frame in Aseprite sprite sheet. + * */ + public static Animation importAnimation(String jsonPath) throws IOException, FileNotFoundException, AsepriteHandler.ImportAnimationException { + + JsonElement rootElement = null; + try { rootElement = getRootJsonElement(jsonPath); } + catch(FileNotFoundException e) { + throw new FileNotFoundException("FileNotFoundException: Could not find .json file " + jsonPath); + } + + String spriteSheetPath = getSpriteSheetPath(rootElement); + File spriteSheetFile = new File(spriteSheetPath); + if(!spriteSheetFile.exists()) { + throw new FileNotFoundException("FileNotFoundException: Could not find sprite sheet file. " + + "Expected location is 'image' in .json metadata, which evaluates to: " + spriteSheetPath); + } + + Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); + Dimension spriteSheetDimensions = getSpriteSheetDimensions(rootElement); + if(areKeyFramesSameDimensions(rootElement, keyFrameDimensions)) { + + BufferedImage image = new BufferedImage((int)spriteSheetDimensions.getWidth(), + (int)spriteSheetDimensions.getHeight(), + BufferedImage.TYPE_4BYTE_ABGR); + + try { image = ImageIO.read(spriteSheetFile); } + catch(IOException e) { + throw new IOException("IOException: Could not write sprite sheet data to BufferedImage object."); + } + + Spritesheet spriteSheet = new Spritesheet(image, + spriteSheetPath, + (int)keyFrameDimensions.getWidth(), + (int)keyFrameDimensions.getHeight()); + + return new Animation(spriteSheet, false, getKeyFrameDurations(rootElement)); + } + + throw new AsepriteHandler.ImportAnimationException("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions."); + } + + /** + * @param jsonPath path (including filename) to Aseprite .json file. + * + * @return root element of JSON data. + * */ + private static JsonElement getRootJsonElement(String jsonPath) throws FileNotFoundException { + + File jsonFile = new File(jsonPath); + + try { + JsonElement rootElement = JsonParser.parseReader(new FileReader(jsonFile)); + return rootElement; + } + catch(FileNotFoundException e) { throw e; } + } + + /** + * @param rootElement root element of JSON data. + * + * @return path (including filename) to animation sprite sheet. + * */ + private static String getSpriteSheetPath(JsonElement rootElement) { + + JsonElement metaData = rootElement.getAsJsonObject().get("meta"); + String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); + + return spriteSheetPath; + } + + /** + * @param rootElement root element of JSON data. + * + * @return dimensions of animation sprite sheet. + * */ + private static Dimension getSpriteSheetDimensions(JsonElement rootElement) { + + JsonElement metadata = rootElement.getAsJsonObject().get("meta"); + JsonObject spriteSheetSize = metadata.getAsJsonObject().get("size").getAsJsonObject(); + + int spriteSheetWidth = spriteSheetSize.get("w").getAsInt(); + int spriteSheetHeight = spriteSheetSize.get("h").getAsInt(); + + return new Dimension(spriteSheetWidth, spriteSheetHeight); + } + + /** + * @param rootElement root element of JSON data. + * + * @return dimensions of first key frame. + * */ + private static Dimension getKeyFrameDimensions(JsonElement rootElement) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); + JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + + return new Dimension(frameWidth, frameHeight); + } + + /** + * @param rootElement root element of JSON data. + * @param expected expected dimensions of each key frame. + * + * @return true if key frames have same duration. + * */ + private static boolean areKeyFramesSameDimensions(JsonElement rootElement, Dimension expected) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + for(Map.Entry entry : frames.getAsJsonObject().entrySet()) { + JsonObject frameObject = entry.getValue().getAsJsonObject(); + JsonObject frameDimensions = frameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + + if(frameWidth != expected.getWidth() || frameHeight != expected.getHeight()) + return false; + } + + return true; + } + + /** + * @param rootElement root element of JSON data. + * + * @return integer array representing duration of each key frame. + * */ + public static int[] getKeyFrameDurations(JsonElement rootElement) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + Set> keyFrameSet = frames.getAsJsonObject().entrySet(); + + int[] keyFrameDurations = new int[keyFrameSet.size()]; + + int frameIndex = 0; + for(Map.Entry entry : keyFrameSet) { + JsonObject frameObject = entry.getValue().getAsJsonObject(); + int frameDuration = frameObject.get("duration").getAsInt(); + keyFrameDurations[frameIndex++] = frameDuration; + } + + return keyFrameDurations; + } } From 0cc51f55f203ff911c9f1aeabe20cc191583b586 Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Mon, 8 Mar 2021 20:29:38 +0100 Subject: [PATCH 14/54] Add test animations used to test Aseprite import Added a new folder intended to contain test animations that can be used for testing the Aseprite import functionality. --- .../Sprite-0001-sheet.png | Bin 0 -> 246 bytes .../aseprite_test_animations/Sprite-0001.json | 40 ++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..44a7c127f9c5aed232b18eeecdd6217ac91ba2e4 GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^2|%pC!3HGX9;gigQhPmJ978f1-`+UL+ibwonz%wj z!`Q%&Eosh~18xsnq5@exHf+rN|GvXx!yh5}7gh`mejS=Ao#j9N-Cn&{#zTQ2nI)lz zp+~U6kjcOeXq?2$?fgkxl~T{wKM&7*tL^#O{!-XRal=-fSdX{!q)ctP+!%DTmo$Hn zc#{z8aI(tP+jq5O`ux{>dk-cVPBM;8{&#&|N`9}sN@eWc*lPbW|JEZ{W4~A2;oNg_ t<+3d-4=dkQ1znvnfBtTuRR`)L7y=JxPf9wqTpY+{@O1TaS?83{1ORfuVI2Sf literal 0 HcmV?d00001 diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json new file mode 100644 index 000000000..e512f005f --- /dev/null +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json @@ -0,0 +1,40 @@ +{ "frames": { + "Sprite-0001 0.png": { + "frame": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + }, + "Sprite-0001 1.png": { + "frame": { "x": 32, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + }, + "Sprite-0001 2.png": { + "frame": { "x": 64, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.1.9-dev", + "image": "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png", + "format": "RGBA8888", + "size": { "w": 96, "h": 32 }, + "scale": "1", + "frameTags": [ + ], + "layers": [ + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" } + ] + } +} From 61ad8270ad472992399f913669d1b517854f08dd Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Mon, 8 Mar 2021 20:33:44 +0100 Subject: [PATCH 15/54] Add unit test for Aseprite animation import Verifies that the import works as expected when given valid input. --- .../animation/AsepriteHandlerTests.java | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java new file mode 100644 index 000000000..bb0438a6f --- /dev/null +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -0,0 +1,52 @@ +package de.gurkenlabs.litiengine.graphics.animation; + +import java.io.IOException; +import java.io.FileNotFoundException; +import java.awt.image.BufferedImage; + +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +import de.gurkenlabs.litiengine.graphics.Spritesheet; +import de.gurkenlabs.litiengine.graphics.animation.Animation; +import de.gurkenlabs.litiengine.resources.ImageFormat; + +public class AsepriteHandlerTests { + + /** + * Tests that Aseprite animation import works as expected when given valid input. + * */ + @Test + public void importAsepriteAnimationTest() { + try { + Animation animation = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json"); + assertEquals("Sprite-0001-sheet", animation.getName()); + assertEquals(300, animation.getTotalDuration()); + for(int keyFrameDuration : animation.getKeyFrameDurations()) + assertEquals(100, keyFrameDuration); + + Spritesheet spriteSheet = animation.getSpritesheet(); + assertEquals(32, spriteSheet.getSpriteHeight()); + assertEquals(32, spriteSheet.getSpriteWidth()); + assertEquals(3, spriteSheet.getTotalNumberOfSprites()); + assertEquals(1, spriteSheet.getRows()); + assertEquals(3, spriteSheet.getColumns()); + assertEquals(ImageFormat.PNG, spriteSheet.getImageFormat()); + + BufferedImage image = spriteSheet.getImage(); + assertEquals(96, image.getWidth()); + assertEquals(32, image.getHeight()); + } + catch(FileNotFoundException e) { + fail(e.getMessage()); + } + catch(IOException e) { + fail(e.getMessage()); + } + catch(AsepriteHandler.ImportAnimationException e) { + fail(e.getMessage()); + } + } +} From 3415a7af1320f93562bcc577a7b193b1cde0369e Mon Sep 17 00:00:00 2001 From: nwessman Date: Mon, 8 Mar 2021 21:02:38 +0100 Subject: [PATCH 16/54] Add javadoc comments to export --- .../graphics/animation/AsepriteHandler.java | 75 +++++++++++++++---- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index dd2f71aa5..3857cc966 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -16,13 +16,33 @@ public class AsepriteHandler { - + /** + * Error that is thrown by the export class + */ + public static class ExportAnimationException extends Error { + public ExportAnimationException(String message) { + super(message); + } + } + + /** + * Creates the json representation of an animation object and prints it. + * This is the public accesible function and can/should be changed to fit into the UI. + * + * @param animation the animation object to export + */ public void exportAnimation(Animation animation){ String json = createJson(animation); System.out.println("JSON: " + json); } + /** + * Creates the json representation of an animation object and returns it as a string. + * + * @param animation animation object to export as json. + * @return the json as a string. + */ private String createJson(Animation animation){ Spritesheet spritesheet = animation.getSpritesheet(); List keyframes = animation.getKeyframes(); @@ -30,7 +50,8 @@ private String createJson(Animation animation){ if(frames.length != spritesheet.getTotalNumberOfSprites()){ //ERROR - System.out.println("ERROR"); + System.out.println("ERROR"); + throw new ExportAnimationException("Different dimensions of keyframes and sprites in spritesheet"); } // Build the frames object in the json @@ -71,9 +92,6 @@ private String createJson(Animation animation){ } } - - - // Build the meta object in the json int spritesheetWidth = frameWidth * numCol; int spritesheetHeight = frameHeight * numRows; @@ -90,8 +108,8 @@ private String createJson(Animation animation){ // Create the json as string Gson gson = new GsonBuilder().setPrettyPrinting().create(); - StringBuilder sb = new StringBuilder(); + sb.append("{ \"frames\": {\n"); for(int i = 0; i < frames.length; i++){ String json = gson.toJson(frames[i]); @@ -104,6 +122,9 @@ private String createJson(Animation animation){ return sb.toString(); } + /** + * Frames class for Aseprite json structure. + */ private class Frames { transient String name; Map frame; @@ -113,6 +134,16 @@ private class Frames { Map sourceSize; int duration; + /** + * + * @param name name of frame + * @param frame x, y, w, h on the substruction of the sprite in the spritesheet. + * @param rotated is the frame rotated? + * @param trimmed is the frame trimmed? + * @param spriteSourceSize how the sprite is trimmed. + * @param sourceSize the original sprite size. + * @param duration the duration of the frame + */ public Frames(String name, Map frame, boolean rotated, boolean trimmed, Map spriteSourceSize, Map sourceSize, int duration){ this.name = name; this.frame = frame; @@ -122,10 +153,11 @@ public Frames(String name, Map frame, boolean rotated, boolean this.sourceSize = sourceSize; this.duration = duration; } - - } + /** + * Meta data class for Aseprite json structure. + */ private class Meta { String app; String version; @@ -135,8 +167,16 @@ private class Meta { String scale; Layer[] layers; - - + /** + * + * @param app the application the json format comes from, in this case Aseprite. + * @param version Version of application. + * @param image filename of spritesheet. + * @param format color format of spritesheet image. + * @param size Size of spritesheet. + * @param scale Scale of spritesheet. + * @param layers Layers of spritesheet. + */ public Meta(String app, String version, String image, String format, Map size, String scale, Layer[] layers){ this.app = app; this.version = version; @@ -145,16 +185,23 @@ public Meta(String app, String version, String image, String format, Map Date: Mon, 8 Mar 2021 21:13:55 +0100 Subject: [PATCH 17/54] Fix test print json This changes so it is the tests that prints the json not the export function. --- .../graphics/animation/AsepriteHandler.java | 15 ++++----------- .../graphics/animation/AsepriteHandlerTests.java | 6 +++++- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 3857cc966..452b032c9 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -26,15 +26,15 @@ public ExportAnimationException(String message) { } /** - * Creates the json representation of an animation object and prints it. + * Creates the json representation of an animation object and returns it. * This is the public accesible function and can/should be changed to fit into the UI. * * @param animation the animation object to export */ - public void exportAnimation(Animation animation){ + public String exportAnimation(Animation animation){ String json = createJson(animation); - System.out.println("JSON: " + json); + return json; } /** @@ -49,8 +49,6 @@ private String createJson(Animation animation){ Frames[] frames = new Frames[keyframes.size()]; if(frames.length != spritesheet.getTotalNumberOfSprites()){ - //ERROR - System.out.println("ERROR"); throw new ExportAnimationException("Different dimensions of keyframes and sprites in spritesheet"); } @@ -208,12 +206,7 @@ public Layer(String name, int opacity, String blendMode){ this.blendMode = blendMode; } - } - - - - - + } } diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index ab145cc26..9694d28b9 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -14,6 +14,9 @@ public class AsepriteHandlerTests { + /** + * Test that just create a json and prints in to standard output. + */ @Test public void exportAnimationTest() { String spritesheetPath = "C:/Users/Nikla/Documents/Programmering/SoftwareFundamentals/Assignment-3-EC/litiengine/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animation/Sprite-0001-sheet.png"; @@ -22,7 +25,8 @@ public void exportAnimationTest() { Animation animation = new Animation(spritesheet, false, false, 2,2,2); AsepriteHandler aseprite = new AsepriteHandler(); - aseprite.exportAnimation(animation); + String result = aseprite.exportAnimation(animation); + System.out.println(result); } } \ No newline at end of file From 88f1d8a513483fbd1e32ea330628ba786787a8c5 Mon Sep 17 00:00:00 2001 From: Yu Zhou Date: Tue, 9 Mar 2021 08:23:47 +0100 Subject: [PATCH 18/54] Add some unit tests to verify the exceptions. --- .../animation/AsepriteHandlerTests.java | 30 +++++++++++++- .../aseprite_test_animations/Sprite-0002.json | 41 +++++++++++++++++++ .../aseprite_test_animations/Sprite-0004.json | 41 +++++++++++++++++++ 3 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index bb0438a6f..8e1a89aa1 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -4,15 +4,16 @@ import java.io.FileNotFoundException; import java.awt.image.BufferedImage; + import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import org.junit.jupiter.api.Test; - import de.gurkenlabs.litiengine.graphics.Spritesheet; import de.gurkenlabs.litiengine.graphics.animation.Animation; import de.gurkenlabs.litiengine.resources.ImageFormat; - +import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler.ImportAnimationException; public class AsepriteHandlerTests { /** @@ -49,4 +50,29 @@ public void importAsepriteAnimationTest() { fail(e.getMessage()); } } + /** + * Test that if AsepriteHandler.ImportAnimationException will be throwed if different frame dimensions are provided. + * + */ + @Test + public void ImportAnimationExceptionTest() { + + Throwable exception = assertThrows(ImportAnimationException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json")); + assertEquals("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions.", exception.getMessage()); + } + /** + * 1.first, we test if FileNotFoundException would be throwed if .json file cannot be found. + * 2.then we test if FileNotFoundException would be throwed if spritesheet file cannot be found. + */ + + + @Test + public void FileNotFoundExceptionTest(){ + Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); + assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); + Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); + assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, which evaluates to: tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", exception_withoutSpriteSheet.getMessage()); + + } + } diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json new file mode 100644 index 000000000..a75131d7d --- /dev/null +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json @@ -0,0 +1,41 @@ +{ "frames": { + "Sprite-0002 0.png": { + "frame": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + }, + "Sprite-0002 1.png": { + "frame": { "x": 32, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 64, "h": 64 }, + "duration": 100 + }, + "Sprite-0002 2.png": { + "frame": { "x": 64, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.1.9-dev", + "image": "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png", + "format": "RGBA8888", + "size": { "w": 96, "h": 32 }, + "scale": "1", + "frameTags": [ + ], + "layers": [ + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" } + ] + } + } + \ No newline at end of file diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json new file mode 100644 index 000000000..d1aed4ced --- /dev/null +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json @@ -0,0 +1,41 @@ +{ "frames": { + "Sprite-0001 0.png": { + "frame": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + }, + "Sprite-0001 1.png": { + "frame": { "x": 32, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + }, + "Sprite-0001 2.png": { + "frame": { "x": 64, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.1.9-dev", + "image": "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", + "format": "RGBA8888", + "size": { "w": 96, "h": 32 }, + "scale": "1", + "frameTags": [ + ], + "layers": [ + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" } + ] + } + } + \ No newline at end of file From e54f4457daac68be350cf5bcc445a31dc738f29e Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Tue, 9 Mar 2021 18:19:53 +0100 Subject: [PATCH 19/54] Fix formatting --- .../graphics/animation/AsepriteHandlerTests.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 8e1a89aa1..d560af6da 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -4,7 +4,6 @@ import java.io.FileNotFoundException; import java.awt.image.BufferedImage; - import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -12,8 +11,9 @@ import org.junit.jupiter.api.Test; import de.gurkenlabs.litiengine.graphics.Spritesheet; import de.gurkenlabs.litiengine.graphics.animation.Animation; -import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler.ImportAnimationException; +import de.gurkenlabs.litiengine.resources.ImageFormat; + public class AsepriteHandlerTests { /** @@ -50,9 +50,9 @@ public void importAsepriteAnimationTest() { fail(e.getMessage()); } } + /** * Test that if AsepriteHandler.ImportAnimationException will be throwed if different frame dimensions are provided. - * */ @Test public void ImportAnimationExceptionTest() { @@ -60,19 +60,18 @@ public void ImportAnimationExceptionTest() { Throwable exception = assertThrows(ImportAnimationException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json")); assertEquals("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions.", exception.getMessage()); } + /** + * Tests thrown FileNotFoundException when importing an Aseprite animation. + * * 1.first, we test if FileNotFoundException would be throwed if .json file cannot be found. * 2.then we test if FileNotFoundException would be throwed if spritesheet file cannot be found. */ - - @Test public void FileNotFoundExceptionTest(){ Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, which evaluates to: tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", exception_withoutSpriteSheet.getMessage()); - } - } From 49a70213afb7b97401dd80984b477cc71d27a49b Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Tue, 9 Mar 2021 18:23:42 +0100 Subject: [PATCH 20/54] Remove redundancy --- .../graphics/animation/AsepriteHandler.java | 22 +------------------ 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index a8f52731e..6d00d4b8d 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -56,13 +56,9 @@ public static Animation importAnimation(String jsonPath) throws IOException, Fil } Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); - Dimension spriteSheetDimensions = getSpriteSheetDimensions(rootElement); if(areKeyFramesSameDimensions(rootElement, keyFrameDimensions)) { - BufferedImage image = new BufferedImage((int)spriteSheetDimensions.getWidth(), - (int)spriteSheetDimensions.getHeight(), - BufferedImage.TYPE_4BYTE_ABGR); - + BufferedImage image = null; try { image = ImageIO.read(spriteSheetFile); } catch(IOException e) { throw new IOException("IOException: Could not write sprite sheet data to BufferedImage object."); @@ -108,22 +104,6 @@ private static String getSpriteSheetPath(JsonElement rootElement) { return spriteSheetPath; } - /** - * @param rootElement root element of JSON data. - * - * @return dimensions of animation sprite sheet. - * */ - private static Dimension getSpriteSheetDimensions(JsonElement rootElement) { - - JsonElement metadata = rootElement.getAsJsonObject().get("meta"); - JsonObject spriteSheetSize = metadata.getAsJsonObject().get("size").getAsJsonObject(); - - int spriteSheetWidth = spriteSheetSize.get("w").getAsInt(); - int spriteSheetHeight = spriteSheetSize.get("h").getAsInt(); - - return new Dimension(spriteSheetWidth, spriteSheetHeight); - } - /** * @param rootElement root element of JSON data. * From 64c8def24af5bac5e2235779937c1251705ba263 Mon Sep 17 00:00:00 2001 From: nwessman Date: Tue, 9 Mar 2021 20:53:55 +0100 Subject: [PATCH 21/54] Change export argument from Animation to SpritesheetResource --- .../graphics/animation/AsepriteHandler.java | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 23d6d60d7..e27e61a8a 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -23,6 +23,8 @@ import de.gurkenlabs.litiengine.graphics.Spritesheet; import de.gurkenlabs.litiengine.graphics.animation.Animation; import de.gurkenlabs.litiengine.graphics.animation.KeyFrame; +import de.gurkenlabs.litiengine.resources.Resources; +import de.gurkenlabs.litiengine.resources.SpritesheetResource; /** * Offers an interface to import Aseprite JSON export format. @@ -189,24 +191,25 @@ public ExportAnimationException(String message) { * Creates the json representation of an animation object and returns it. * This is the public accesible function and can/should be changed to fit into the UI. * - * @param animation the animation object to export + * @param spritesheetResource the animation object to export */ - public String exportAnimation(Animation animation){ + public String exportAnimation(SpritesheetResource spritesheetResource){ - String json = createJson(animation); + String json = createJson(spritesheetResource); return json; } /** * Creates the json representation of an animation object and returns it as a string. * - * @param animation animation object to export as json. + * @param spritesheetResource spritesheetResource object to export as json. * @return the json as a string. */ - private String createJson(Animation animation){ - Spritesheet spritesheet = animation.getSpritesheet(); - List keyframes = animation.getKeyframes(); - Frames[] frames = new Frames[keyframes.size()]; + private String createJson(SpritesheetResource spritesheetResource){ + Spritesheet spritesheet = Resources.spritesheets().load(spritesheetResource); + assert spritesheet != null; + int[] keyframes = Resources.spritesheets().getCustomKeyFrameDurations(spritesheet); + Frames[] frames = new Frames[keyframes.length]; if(frames.length != spritesheet.getTotalNumberOfSprites()){ throw new ExportAnimationException("Different dimensions of keyframes and sprites in spritesheet"); @@ -238,7 +241,7 @@ private String createJson(Animation animation){ put("w", frameWidth); put("h", frameHeight); }}; - int duration = keyframes.get(i+j).getDuration(); + int duration = keyframes[i+j]; String index = String.valueOf(i+j); frames[i+j] = new Frames("frame " + index, frame, From 77ebd3dde262e952af8f931bc08cf1c7a0d056eb Mon Sep 17 00:00:00 2001 From: nwessman Date: Tue, 9 Mar 2021 20:54:19 +0100 Subject: [PATCH 22/54] Fix test so it uses SpritesourceResource --- .../graphics/animation/AsepriteHandlerTests.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 79336380c..3c337b4f5 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -13,6 +13,8 @@ import de.gurkenlabs.litiengine.graphics.animation.Animation; import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler.ImportAnimationException; import de.gurkenlabs.litiengine.resources.ImageFormat; +import de.gurkenlabs.litiengine.resources.SpritesheetResource; + public class AsepriteHandlerTests { @@ -84,9 +86,12 @@ public void exportAnimationTest() { BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); Animation animation = new Animation(spritesheet, false, false, 2,2,2); - + int[] keyFrames = animation.getKeyFrameDurations(); + SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); + spritesheetResource.setKeyframes(keyFrames); + AsepriteHandler aseprite = new AsepriteHandler(); - String result = aseprite.exportAnimation(animation); + String result = aseprite.exportAnimation(spritesheetResource); System.out.println(result); } } From 9c64b2c62614749cd17b9ebfc608650803c9139d Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Tue, 9 Mar 2021 23:00:01 +0100 Subject: [PATCH 23/54] Editor integration Added two functions for importing animations. They work much like importspritesheet --- .../gurkenlabs/utiliti/components/Editor.java | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java index d95dfdb15..fb1da5aec 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java +++ b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java @@ -1,5 +1,4 @@ package de.gurkenlabs.utiliti.components; - import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; @@ -30,6 +29,16 @@ import javax.swing.filechooser.FileNameExtensionFilter; import javax.xml.bind.JAXBException; +import de.gurkenlabs.litiengine.Game; +import de.gurkenlabs.litiengine.environment.tilemap.IImageLayer; +import de.gurkenlabs.litiengine.environment.tilemap.ITileset; +import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterData; +import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterLoader; +import de.gurkenlabs.litiengine.gui.screens.Screen; +import de.gurkenlabs.litiengine.resources.ImageFormat; +import de.gurkenlabs.litiengine.resources.ResourceBundle; +import de.gurkenlabs.litiengine.resources.Resources; +import de.gurkenlabs.litiengine.resources.SoundFormat; import de.gurkenlabs.litiengine.Game; import de.gurkenlabs.litiengine.environment.tilemap.IImageLayer; import de.gurkenlabs.litiengine.environment.tilemap.ITileset; @@ -41,7 +50,6 @@ import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterData; import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterLoader; import de.gurkenlabs.litiengine.gui.screens.Screen; -import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.ResourceBundle; import de.gurkenlabs.litiengine.resources.Resources; import de.gurkenlabs.litiengine.resources.SoundFormat; @@ -77,6 +85,7 @@ public class Editor extends Screen { private static final String TEXTUREATLAS_FILE_NAME = "Texture Atlas XML (generic)"; private static final String IMPORT_DIALOGUE = "import_something"; + private static final String ANIMATION_FILE_NAME = "Animation file"; private static Editor instance; private static UserPreferences preferences; @@ -380,6 +389,12 @@ public void importSpriteSheets() { } } + public void importAnimation() { + if (EditorFileChooser.showFileDialog(ANIMATION_FILE_NAME, Resources.strings().get(IMPORT_DIALOGUE, ANIMATION_FILE_NAME), false, "json") == JFileChooser.APPROVE_OPTION) { + this.processAnimation(EditorFileChooser.instance().getSelectedFile()); + } + } + public void importSounds() { if (EditorFileChooser.showFileDialog(AUDIO_FILE_NAME, Resources.strings().get(IMPORT_DIALOGUE, AUDIO_FILE_NAME), true, SoundFormat.getAllExtensions()) == JFileChooser.APPROVE_OPTION) { this.importSounds(EditorFileChooser.instance().getSelectedFiles()); @@ -488,6 +503,30 @@ private void processSpritesheets(SpritesheetImportPanel spritePanel) { this.loadSpriteSheets(sprites, true); } + /** + * Loads an animation (spritesheet with keyframes) in to the editor + * @param file - a json file, encoded by the asesprite export standard + */ + public void processAnimation(File file) { + try { + Animation animation = AsepriteHandler.importAnimation(file.getAbsolutePath()); + int[] keyFrames = animation.getKeyFrameDurations(); + SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); + spritesheetResource.setKeyframes(keyFrames); + Collection sprites = new ArrayList<>(Collections.singleton(spritesheetResource)); + for (SpritesheetResource info : sprites) { + Resources.spritesheets().getAll().removeIf(x -> x.getName().equals(info.getName() + "-preview")); + this.getGameFile().getSpriteSheets().removeIf(x -> x.getName().equals(info.getName())); + this.getGameFile().getSpriteSheets().add(info); + log.log(Level.INFO, "imported spritesheet {0}", new Object[]{info.getName()}); + } + this.loadSpriteSheets(sprites, true); + + } catch (IOException e) { + e.printStackTrace(); + } + } + public void importEmitters() { XmlImportDialog.importXml("Emitter", file -> { EmitterData emitter; @@ -793,4 +832,4 @@ private void gamefileLoaded() { callback.run(); } } -} \ No newline at end of file +} From cb98f95d7c3d972a16ab0eb108512073cfbadb6d Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Tue, 9 Mar 2021 23:04:54 +0100 Subject: [PATCH 24/54] Update Editor.java Changed imports --- .../de/gurkenlabs/utiliti/components/Editor.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java index fb1da5aec..6567da823 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java +++ b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java @@ -1,4 +1,5 @@ package de.gurkenlabs.utiliti.components; + import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; @@ -29,16 +30,6 @@ import javax.swing.filechooser.FileNameExtensionFilter; import javax.xml.bind.JAXBException; -import de.gurkenlabs.litiengine.Game; -import de.gurkenlabs.litiengine.environment.tilemap.IImageLayer; -import de.gurkenlabs.litiengine.environment.tilemap.ITileset; -import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterData; -import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterLoader; -import de.gurkenlabs.litiengine.gui.screens.Screen; -import de.gurkenlabs.litiengine.resources.ImageFormat; -import de.gurkenlabs.litiengine.resources.ResourceBundle; -import de.gurkenlabs.litiengine.resources.Resources; -import de.gurkenlabs.litiengine.resources.SoundFormat; import de.gurkenlabs.litiengine.Game; import de.gurkenlabs.litiengine.environment.tilemap.IImageLayer; import de.gurkenlabs.litiengine.environment.tilemap.ITileset; @@ -47,9 +38,12 @@ import de.gurkenlabs.litiengine.environment.tilemap.xml.TmxMap; import de.gurkenlabs.litiengine.graphics.Spritesheet; import de.gurkenlabs.litiengine.graphics.TextRenderer; +import de.gurkenlabs.litiengine.graphics.animation.Animation; +import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler; import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterData; import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterLoader; import de.gurkenlabs.litiengine.gui.screens.Screen; +import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.ResourceBundle; import de.gurkenlabs.litiengine.resources.Resources; import de.gurkenlabs.litiengine.resources.SoundFormat; From eccad3c1c97d1b17f4d119a003f6d31718b3a76b Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Tue, 9 Mar 2021 23:25:15 +0100 Subject: [PATCH 25/54] Update ResourcesMenu.java Added UI elements to resourcemenu for import --- .../de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java b/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java index 3107eb7fe..1531483ae 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java @@ -54,6 +54,10 @@ public ResourcesMenu() { exportSpriteSheets.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK)); exportSpriteSheets.addActionListener(a -> Editor.instance().exportSpriteSheets()); + JMenuItem importAnimation = new JMenuItem(Resources.strings().get("menu_assets_importAnimation")); + importAnimation.addActionListener(a -> Editor.instance().importAnimation()); + importAnimation.setEnabled(false); + Editor.instance().onLoaded(() -> { importSpriteFile.setEnabled(Editor.instance().getCurrentResourceFile() != null); importSprite.setEnabled(Editor.instance().getCurrentResourceFile() != null); @@ -63,6 +67,7 @@ public ResourcesMenu() { importTilesets.setEnabled(Editor.instance().getCurrentResourceFile() != null); importSounds.setEnabled(Editor.instance().getCurrentResourceFile() != null); exportSpriteSheets.setEnabled(Editor.instance().getCurrentResourceFile() != null); + importAnimation.setEnabled(Editor.instance().getCurrentResourceFile() != null); }); this.add(importSprite); @@ -72,7 +77,8 @@ public ResourcesMenu() { this.add(importBlueprints); this.add(importTilesets); this.add(importSounds); - this.addSeparator(); + this.add(importAnimation); + this.addSeparator(); this.add(exportSpriteSheets); this.add(compress); } From 51b9171db7c86ab599d64de25220b67f94336f1a Mon Sep 17 00:00:00 2001 From: Yu Zhou Date: Wed, 10 Mar 2021 00:31:50 +0100 Subject: [PATCH 26/54] Add some unit tests to exportAnimation method. --- .../animation/AsepriteHandlerTests.java | 48 ++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 3c337b4f5..dbeb84fd8 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -1,5 +1,8 @@ package de.gurkenlabs.litiengine.graphics.animation; +import java.io.File; +import java.io.FileReader; + import java.io.IOException; import java.io.FileNotFoundException; import java.awt.image.BufferedImage; @@ -8,6 +11,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; import de.gurkenlabs.litiengine.graphics.Spritesheet; import de.gurkenlabs.litiengine.graphics.animation.Animation; @@ -15,6 +19,12 @@ import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.SpritesheetResource; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; +import com.google.gson.JsonElement; +import com.google.gson.JsonParser; +import com.google.gson.JsonObject; public class AsepriteHandlerTests { @@ -78,7 +88,7 @@ public void FileNotFoundExceptionTest(){ } /** - * Test that just create a json and prints in to standard output. + * Test that just create a json. Select some entries in json file to test. */ @Test public void exportAnimationTest() { @@ -92,6 +102,40 @@ public void exportAnimationTest() { AsepriteHandler aseprite = new AsepriteHandler(); String result = aseprite.exportAnimation(spritesheetResource); - System.out.println(result); + + File asepriteJsonFile = new File(result); + try { + JsonElement rootElement = JsonParser.parseReader(new FileReader(asepriteJsonFile)); + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); + JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + assertEquals(32, frameWidth); + assertEquals(32, frameHeight); + + int duration = firstFrameObject.get("duration").getAsInt(); + assertEquals(100, duration); + + JsonElement meta = rootElement.getAsJsonObject().get("meta"); + JsonObject size = meta.getAsJsonObject().get("size").getAsJsonObject(); + int metaWidth = size.get("w").getAsInt(); + int metaHeight = size.get("h").getAsInt(); + assertEquals(96, metaWidth); + assertEquals(32, metaHeight); + + JsonElement layers = meta.getAsJsonObject().get("layers"); + int opacity = layers.getAsJsonArray().get(0).getAsJsonObject().get("opacity").getAsInt(); + assertEquals(255, opacity); + + + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + + + } } From 772565a917095ec5173c0c8cbcbb13eb973b2467 Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 09:10:18 +0100 Subject: [PATCH 27/54] Update AssetPanelItem.java Integration for export. Changed if else statements to switch --- .../utiliti/swing/AssetPanelItem.java | 59 ++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java index 240fd1b9c..f6572d55a 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java @@ -11,6 +11,8 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; +import java.io.FileWriter; +import java.io.Writer; import java.io.FileOutputStream; import java.io.IOException; import java.util.Collection; @@ -48,7 +50,9 @@ import de.gurkenlabs.litiengine.environment.tilemap.xml.MapObject; import de.gurkenlabs.litiengine.environment.tilemap.xml.Tileset; import de.gurkenlabs.litiengine.graphics.Spritesheet; +import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler; import de.gurkenlabs.litiengine.graphics.emitters.xml.EmitterData; +import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler; import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.Resources; import de.gurkenlabs.litiengine.resources.SoundFormat; @@ -441,20 +445,47 @@ private void exportSpritesheet() { chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setDialogType(JFileChooser.SAVE_DIALOG); chooser.setDialogTitle("Export Spritesheet"); - if (answer == 0) { - XmlExportDialog.export(spriteSheetInfo, "Spritesheet", spriteSheetInfo.getName()); - } else if (answer == 1) { - FileFilter filter = new FileNameExtensionFilter(format.toString() + " - Image", format.toString()); - chooser.setFileFilter(filter); - chooser.addChoosableFileFilter(filter); - chooser.setSelectedFile(new File(spriteSheetInfo.getName() + format.toFileExtension())); - - int result = chooser.showSaveDialog(Game.window().getRenderComponent()); - if (result == JFileChooser.APPROVE_OPTION) { - ImageSerializer.saveImage(chooser.getSelectedFile().toString(), sprite.getImage(), format); - log.log(Level.INFO, "exported spritesheet {0} to {1}", new Object[] { spriteSheetInfo.getName(), chooser.getSelectedFile() }); - } - } + switch (answer) { + case 0: { + XmlExportDialog.export(spriteSheetInfo, "Spritesheet", spriteSheetInfo.getName()); + break; + } + case 1: { + FileFilter filter = new FileNameExtensionFilter(format.toString() + " - Image", format.toString()); + chooser.setFileFilter(filter); + chooser.addChoosableFileFilter(filter); + chooser.setSelectedFile(new File(spriteSheetInfo.getName() + format.toFileExtension())); + + int result = chooser.showSaveDialog(Game.window().getRenderComponent()); + if (result == JFileChooser.APPROVE_OPTION) { + ImageSerializer.saveImage(chooser.getSelectedFile().toString(), sprite.getImage(), format); + log.log(Level.INFO, "exported spritesheet {0} to {1}", new Object[]{spriteSheetInfo.getName(), chooser.getSelectedFile()}); + } + break; + } + case 2: { + FileFilter filter = new FileNameExtensionFilter(".json" + " - " + "Spritesheet" + " JSON", "json"); + chooser.setFileFilter(filter); + chooser.addChoosableFileFilter(filter); + chooser.setSelectedFile(new File(spriteSheetInfo.getName() + "." + "json")); + + int result = chooser.showSaveDialog(Game.window().getRenderComponent()); + if (result == JFileChooser.APPROVE_OPTION) { + String fileNameWithExtension = chooser.getSelectedFile().toString(); + if (!fileNameWithExtension.endsWith(".json")) { + fileNameWithExtension += ".json"; + } + String json = AsepriteHandler.exportAnimation(spriteSheetInfo); + try (Writer writer = new FileWriter(fileNameWithExtension)) { + writer.write(json); + log.log(Level.INFO, "Exported {0} {1} to {2}", new Object[]{"Spritesheet", spriteSheetInfo.getName(), fileNameWithExtension}); + } catch (IOException e) { + e.printStackTrace(); + } + } + break; + } + } } catch (IOException e) { log.log(Level.SEVERE, e.getMessage(), e); } From 61878d8ce2be84bf4422495a9e56831075b5d1b3 Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 09:24:53 +0100 Subject: [PATCH 28/54] Update AsepriteHandler.java Added static modifiers --- .../litiengine/graphics/animation/AsepriteHandler.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index e27e61a8a..ff1feef90 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -193,7 +193,7 @@ public ExportAnimationException(String message) { * * @param spritesheetResource the animation object to export */ - public String exportAnimation(SpritesheetResource spritesheetResource){ + public static String exportAnimation(SpritesheetResource spritesheetResource){ String json = createJson(spritesheetResource); return json; @@ -205,7 +205,7 @@ public String exportAnimation(SpritesheetResource spritesheetResource){ * @param spritesheetResource spritesheetResource object to export as json. * @return the json as a string. */ - private String createJson(SpritesheetResource spritesheetResource){ + private static String createJson(SpritesheetResource spritesheetResource){ Spritesheet spritesheet = Resources.spritesheets().load(spritesheetResource); assert spritesheet != null; int[] keyframes = Resources.spritesheets().getCustomKeyFrameDurations(spritesheet); @@ -286,8 +286,8 @@ private String createJson(SpritesheetResource spritesheetResource){ /** * Frames class for Aseprite json structure. */ - private class Frames { transient String name; + private static class Frames { Map frame; boolean rotated; boolean trimmed; @@ -319,7 +319,7 @@ public Frames(String name, Map frame, boolean rotated, boolean /** * Meta data class for Aseprite json structure. */ - private class Meta { + private static class Meta { String app; String version; String image; @@ -352,7 +352,7 @@ public Meta(String app, String version, String image, String format, Map Date: Wed, 10 Mar 2021 09:27:57 +0100 Subject: [PATCH 29/54] Update AsepriteHandler.java Forgot a field --- .../litiengine/graphics/animation/AsepriteHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index ff1feef90..63e465bbd 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -286,9 +286,9 @@ private static String createJson(SpritesheetResource spritesheetResource){ /** * Frames class for Aseprite json structure. */ - transient String name; private static class Frames { - Map frame; + transient String name; + Map frame; boolean rotated; boolean trimmed; Map spriteSourceSize; From 4336bc9993a82d4a5b99326dad28bcd7b800a49a Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 09:39:55 +0100 Subject: [PATCH 30/54] Update strings.properties Added string resource for import animation --- utiliti/localization/strings.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/utiliti/localization/strings.properties b/utiliti/localization/strings.properties index 3f08e7d9b..d875be8e4 100644 --- a/utiliti/localization/strings.properties +++ b/utiliti/localization/strings.properties @@ -58,6 +58,7 @@ menu_assets_importBlueprints=Import Blueprints... menu_assets_importTilesets=Import Tilesets... menu_assets_importSounds=Import Sounds... menu_assets_editSprite=Edit Spritesheet(s) +menu_assets_importAnimation=Import Animation... menu_help=Help menu_help_utiliti=utiLITI From 34d8a019002ff31779efe4242e06f0d4798b7895 Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 09:54:42 +0100 Subject: [PATCH 31/54] Update AssetPanelItem.java Added json option --- utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java index f6572d55a..d7b3219ad 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java @@ -435,7 +435,7 @@ private void exportSpritesheet() { ImageFormat format = sprite.getImageFormat() != ImageFormat.UNSUPPORTED ? sprite.getImageFormat() : ImageFormat.PNG; - Object[] options = { ".xml", format.toFileExtension() }; + Object[] options = { ".xml", format.toFileExtension(), ".json"}; int answer = JOptionPane.showOptionDialog(Game.window().getRenderComponent(), "Select an export format:", "Export Spritesheet", JOptionPane.DEFAULT_OPTION, JOptionPane.PLAIN_MESSAGE, null, options, options[0]); try { From 8581bbc7e64110e1280554dc68b6535cb166dfc4 Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 10:03:13 +0100 Subject: [PATCH 32/54] Update AsepriteHandler.java Ran autoformat --- .../graphics/animation/AsepriteHandler.java | 675 +++++++++--------- 1 file changed, 334 insertions(+), 341 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 63e465bbd..bfebda2da 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -29,345 +29,338 @@ /** * Offers an interface to import Aseprite JSON export format. * Note: requires animation key frames to have same dimensions to support internal animation format. - * */ + */ public class AsepriteHandler { - - /** - * Thrown to indicate error when importing Aseprite JSON format. - * */ - public static class ImportAnimationException extends Error { - public ImportAnimationException(String message) { - super(message); - } - } - - /** - * Imports an Aseprite animation (.json + sprite sheet). - * Note: searches for sprite sheet path through .json metadata, specifically 'image' element. This should be an absolute path in system. - * - * @param jsonPath path (including filename) to Aseprite JSON. - * - * @return Animation object represented by each key frame in Aseprite sprite sheet. - * */ - public static Animation importAnimation(String jsonPath) throws IOException, FileNotFoundException, AsepriteHandler.ImportAnimationException { - - JsonElement rootElement = null; - try { rootElement = getRootJsonElement(jsonPath); } - catch(FileNotFoundException e) { - throw new FileNotFoundException("FileNotFoundException: Could not find .json file " + jsonPath); - } - - String spriteSheetPath = getSpriteSheetPath(rootElement); - File spriteSheetFile = new File(spriteSheetPath); - if(!spriteSheetFile.exists()) { - throw new FileNotFoundException("FileNotFoundException: Could not find sprite sheet file. " + - "Expected location is 'image' in .json metadata, which evaluates to: " + spriteSheetPath); - } - - Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); - if(areKeyFramesSameDimensions(rootElement, keyFrameDimensions)) { - - BufferedImage image = null; - try { image = ImageIO.read(spriteSheetFile); } - catch(IOException e) { - throw new IOException("IOException: Could not write sprite sheet data to BufferedImage object."); - } - - Spritesheet spriteSheet = new Spritesheet(image, - spriteSheetPath, - (int)keyFrameDimensions.getWidth(), - (int)keyFrameDimensions.getHeight()); - - return new Animation(spriteSheet, false, getKeyFrameDurations(rootElement)); - } - - throw new AsepriteHandler.ImportAnimationException("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions."); - } - - /** - * @param jsonPath path (including filename) to Aseprite .json file. - * - * @return root element of JSON data. - * */ - private static JsonElement getRootJsonElement(String jsonPath) throws FileNotFoundException { - - File jsonFile = new File(jsonPath); - - try { - JsonElement rootElement = JsonParser.parseReader(new FileReader(jsonFile)); - return rootElement; - } - catch(FileNotFoundException e) { throw e; } - } - - /** - * @param rootElement root element of JSON data. - * - * @return path (including filename) to animation sprite sheet. - * */ - private static String getSpriteSheetPath(JsonElement rootElement) { - - JsonElement metaData = rootElement.getAsJsonObject().get("meta"); - String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); - - return spriteSheetPath; - } - - /** - * @param rootElement root element of JSON data. - * - * @return dimensions of first key frame. - * */ - private static Dimension getKeyFrameDimensions(JsonElement rootElement) { - - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - - JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); - JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); - - int frameWidth = frameDimensions.get("w").getAsInt(); - int frameHeight = frameDimensions.get("h").getAsInt(); - - return new Dimension(frameWidth, frameHeight); - } - - /** - * @param rootElement root element of JSON data. - * @param expected expected dimensions of each key frame. - * - * @return true if key frames have same duration. - * */ - private static boolean areKeyFramesSameDimensions(JsonElement rootElement, Dimension expected) { - - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - - for(Map.Entry entry : frames.getAsJsonObject().entrySet()) { - JsonObject frameObject = entry.getValue().getAsJsonObject(); - JsonObject frameDimensions = frameObject.get("sourceSize").getAsJsonObject(); - - int frameWidth = frameDimensions.get("w").getAsInt(); - int frameHeight = frameDimensions.get("h").getAsInt(); - - if(frameWidth != expected.getWidth() || frameHeight != expected.getHeight()) - return false; - } - - return true; - } - - /** - * @param rootElement root element of JSON data. - * - * @return integer array representing duration of each key frame. - * */ - public static int[] getKeyFrameDurations(JsonElement rootElement) { - - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - - Set> keyFrameSet = frames.getAsJsonObject().entrySet(); - - int[] keyFrameDurations = new int[keyFrameSet.size()]; - - int frameIndex = 0; - for(Map.Entry entry : keyFrameSet) { - JsonObject frameObject = entry.getValue().getAsJsonObject(); - int frameDuration = frameObject.get("duration").getAsInt(); - keyFrameDurations[frameIndex++] = frameDuration; - } - - return keyFrameDurations; - } - - /** - * Error that is thrown by the export class - */ - public static class ExportAnimationException extends Error { - public ExportAnimationException(String message) { - super(message); - } - } - - /** - * Creates the json representation of an animation object and returns it. - * This is the public accesible function and can/should be changed to fit into the UI. - * - * @param spritesheetResource the animation object to export - */ - public static String exportAnimation(SpritesheetResource spritesheetResource){ - - String json = createJson(spritesheetResource); - return json; - } - - /** - * Creates the json representation of an animation object and returns it as a string. - * - * @param spritesheetResource spritesheetResource object to export as json. - * @return the json as a string. - */ - private static String createJson(SpritesheetResource spritesheetResource){ - Spritesheet spritesheet = Resources.spritesheets().load(spritesheetResource); - assert spritesheet != null; - int[] keyframes = Resources.spritesheets().getCustomKeyFrameDurations(spritesheet); - Frames[] frames = new Frames[keyframes.length]; - - if(frames.length != spritesheet.getTotalNumberOfSprites()){ - throw new ExportAnimationException("Different dimensions of keyframes and sprites in spritesheet"); - } - - // Build the frames object in the json - int numCol = spritesheet.getColumns(); - int numRows = spritesheet.getRows(); - int frameWidth = spritesheet.getSpriteWidth(); - int frameHeight = spritesheet.getSpriteHeight(); - - for(int i = 0; i < numRows; i++){ - for(int j = 0; j < numCol; j++){ - final int row = i; - final int col = j; - Map frame = new HashMap<>(){{ - put("x", (0 + col*frameWidth) ); - put("y", (0 + row*frameHeight) ); - put("w", frameWidth); - put("h", frameHeight); - }}; - Map spriteSourceSize = new HashMap<>(){{ - put("x", 0); - put("y", 0); - put("w", frameWidth); - put("h", frameHeight); - }}; - Map sourceSize = new HashMap<>(){{ - put("w", frameWidth); - put("h", frameHeight); - }}; - int duration = keyframes[i+j]; - String index = String.valueOf(i+j); - frames[i+j] = new Frames("frame " + index, - frame, - false, - false, - spriteSourceSize, - sourceSize, - duration); - } - } - - // Build the meta object in the json - int spritesheetWidth = frameWidth * numCol; - int spritesheetHeight = frameHeight * numRows; - Map size= new HashMap<>(){{ - put("w", spritesheetWidth); - put("h", spritesheetHeight); - }}; - String spritesheetName = spritesheet.getName(); - Layer[] layers = {new Layer("Layer",255,"normal")}; - Meta meta = new Meta("http://www.aseprite.org/", - "1.2.16.3-x64", - spritesheetName, - "RGBA8888", size, "1", layers); - - // Create the json as string - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - StringBuilder sb = new StringBuilder(); - - sb.append("{ \"frames\": {\n"); - for(int i = 0; i < frames.length; i++){ - String json = gson.toJson(frames[i]); - sb.append(" \"" + frames[i].name + "\": ").append(json).append(",\n"); - } - sb.append(" },\n"); - String json = gson.toJson(meta); - sb.append("\"meta\":").append(json).append("\n}"); - - return sb.toString(); - } - - /** - * Frames class for Aseprite json structure. - */ - private static class Frames { - transient String name; - Map frame; - boolean rotated; - boolean trimmed; - Map spriteSourceSize; - Map sourceSize; - int duration; - - /** - * - * @param name name of frame - * @param frame x, y, w, h on the substruction of the sprite in the spritesheet. - * @param rotated is the frame rotated? - * @param trimmed is the frame trimmed? - * @param spriteSourceSize how the sprite is trimmed. - * @param sourceSize the original sprite size. - * @param duration the duration of the frame - */ - public Frames(String name, Map frame, boolean rotated, boolean trimmed, Map spriteSourceSize, Map sourceSize, int duration){ - this.name = name; - this.frame = frame; - this.rotated = rotated; - this.trimmed = trimmed; - this.spriteSourceSize = spriteSourceSize; - this.sourceSize = sourceSize; - this.duration = duration; - } - } - - /** - * Meta data class for Aseprite json structure. - */ - private static class Meta { - String app; - String version; - String image; - String format; - Map size; - String scale; - Layer[] layers; - - /** - * - * @param app the application the json format comes from, in this case Aseprite. - * @param version Version of application. - * @param image filename of spritesheet. - * @param format color format of spritesheet image. - * @param size Size of spritesheet. - * @param scale Scale of spritesheet. - * @param layers Layers of spritesheet. - */ - public Meta(String app, String version, String image, String format, Map size, String scale, Layer[] layers){ - this.app = app; - this.version = version; - this.image = image; - this.format = format; - this.size = size; - this. scale = scale; - this.layers = layers; - } - } - - /** - * Layer class for Aseprite json structure. - */ - private static class Layer { - String name; - int opacity; - String blendMode; - - /** - * - * @param name Name of layer. - * @param opacity Opacity level of layer. - * @param blendMode Blendmode of layer. - */ - public Layer(String name, int opacity, String blendMode){ - this.name = name; - this.opacity = opacity; - this.blendMode = blendMode; - } - - } -} \ No newline at end of file + + /** + * Thrown to indicate error when importing Aseprite JSON format. + */ + public static class ImportAnimationException extends Error { + public ImportAnimationException(String message) { + super(message); + } + } + + /** + * Imports an Aseprite animation (.json + sprite sheet). + * Note: searches for sprite sheet path through .json metadata, specifically 'image' element. This should be an absolute path in system. + * + * @param jsonPath path (including filename) to Aseprite JSON. + * @return Animation object represented by each key frame in Aseprite sprite sheet. + */ + public static Animation importAnimation(String jsonPath) throws IOException, FileNotFoundException, AsepriteHandler.ImportAnimationException { + + JsonElement rootElement = null; + try { + rootElement = getRootJsonElement(jsonPath); + } catch (FileNotFoundException e) { + throw new FileNotFoundException("FileNotFoundException: Could not find .json file " + jsonPath); + } + + String spriteSheetPath = getSpriteSheetPath(rootElement); + File spriteSheetFile = new File(spriteSheetPath); + if (!spriteSheetFile.exists()) { + throw new FileNotFoundException("FileNotFoundException: Could not find sprite sheet file. " + + "Expected location is 'image' in .json metadata, which evaluates to: " + spriteSheetPath); + } + + Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); + if (areKeyFramesSameDimensions(rootElement, keyFrameDimensions)) { + + BufferedImage image = null; + try { + image = ImageIO.read(spriteSheetFile); + } catch (IOException e) { + throw new IOException("IOException: Could not write sprite sheet data to BufferedImage object."); + } + + Spritesheet spriteSheet = new Spritesheet(image, + spriteSheetPath, + (int) keyFrameDimensions.getWidth(), + (int) keyFrameDimensions.getHeight()); + + return new Animation(spriteSheet, false, getKeyFrameDurations(rootElement)); + } + + throw new AsepriteHandler.ImportAnimationException("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions."); + } + + /** + * @param jsonPath path (including filename) to Aseprite .json file. + * @return root element of JSON data. + */ + private static JsonElement getRootJsonElement(String jsonPath) throws FileNotFoundException { + + File jsonFile = new File(jsonPath); + + try { + JsonElement rootElement = JsonParser.parseReader(new FileReader(jsonFile)); + return rootElement; + } catch (FileNotFoundException e) { + throw e; + } + } + + /** + * @param rootElement root element of JSON data. + * @return path (including filename) to animation sprite sheet. + */ + private static String getSpriteSheetPath(JsonElement rootElement) { + + JsonElement metaData = rootElement.getAsJsonObject().get("meta"); + String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); + + return spriteSheetPath; + } + + /** + * @param rootElement root element of JSON data. + * @return dimensions of first key frame. + */ + private static Dimension getKeyFrameDimensions(JsonElement rootElement) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); + JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + + return new Dimension(frameWidth, frameHeight); + } + + /** + * @param rootElement root element of JSON data. + * @param expected expected dimensions of each key frame. + * @return true if key frames have same duration. + */ + private static boolean areKeyFramesSameDimensions(JsonElement rootElement, Dimension expected) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + for (Map.Entry entry : frames.getAsJsonObject().entrySet()) { + JsonObject frameObject = entry.getValue().getAsJsonObject(); + JsonObject frameDimensions = frameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + + if (frameWidth != expected.getWidth() || frameHeight != expected.getHeight()) + return false; + } + + return true; + } + + /** + * @param rootElement root element of JSON data. + * @return integer array representing duration of each key frame. + */ + public static int[] getKeyFrameDurations(JsonElement rootElement) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + Set> keyFrameSet = frames.getAsJsonObject().entrySet(); + + int[] keyFrameDurations = new int[keyFrameSet.size()]; + + int frameIndex = 0; + for (Map.Entry entry : keyFrameSet) { + JsonObject frameObject = entry.getValue().getAsJsonObject(); + int frameDuration = frameObject.get("duration").getAsInt(); + keyFrameDurations[frameIndex++] = frameDuration; + } + + return keyFrameDurations; + } + + /** + * Error that is thrown by the export class + */ + public static class ExportAnimationException extends Error { + public ExportAnimationException(String message) { + super(message); + } + } + + /** + * Creates the json representation of an animation object and returns it. + * This is the public accesible function and can/should be changed to fit into the UI. + * + * @param spritesheetResource the animation object to export + */ + public static String exportAnimation(SpritesheetResource spritesheetResource) { + String json = createJson(spritesheetResource); + return json; + } + + /** + * Creates the json representation of an animation object and returns it as a string. + * + * @param spritesheetResource spritesheetResource object to export as json. + * @return the json as a string. + */ + private static String createJson(SpritesheetResource spritesheetResource) { + Spritesheet spritesheet = Resources.spritesheets().load(spritesheetResource); + assert spritesheet != null; + int[] keyframes = Resources.spritesheets().getCustomKeyFrameDurations(spritesheet); + Frames[] frames = new Frames[keyframes.length]; + + if (frames.length != spritesheet.getTotalNumberOfSprites()) { + throw new ExportAnimationException("Different dimensions of keyframes and sprites in spritesheet"); + } + + // Build the frames object in the json + int numCol = spritesheet.getColumns(); + int numRows = spritesheet.getRows(); + int frameWidth = spritesheet.getSpriteWidth(); + int frameHeight = spritesheet.getSpriteHeight(); + + for (int i = 0; i < numRows; i++) { + for (int j = 0; j < numCol; j++) { + final int row = i; + final int col = j; + Map frame = new HashMap<>() {{ + put("x", (0 + col * frameWidth)); + put("y", (0 + row * frameHeight)); + put("w", frameWidth); + put("h", frameHeight); + }}; + Map spriteSourceSize = new HashMap<>() {{ + put("x", 0); + put("y", 0); + put("w", frameWidth); + put("h", frameHeight); + }}; + Map sourceSize = new HashMap<>() {{ + put("w", frameWidth); + put("h", frameHeight); + }}; + int duration = keyframes[i + j]; + String index = String.valueOf(i + j); + frames[i + j] = new Frames("frame " + index, + frame, + false, + false, + spriteSourceSize, + sourceSize, + duration); + } + } + + // Build the meta object in the json + int spritesheetWidth = frameWidth * numCol; + int spritesheetHeight = frameHeight * numRows; + Map size = new HashMap<>() {{ + put("w", spritesheetWidth); + put("h", spritesheetHeight); + }}; + String spritesheetName = spritesheet.getName(); + Layer[] layers = {new Layer("Layer", 255, "normal")}; + Meta meta = new Meta("http://www.aseprite.org/", + "1.2.16.3-x64", + spritesheetName, + "RGBA8888", size, "1", layers); + + // Create the json as string + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + StringBuilder sb = new StringBuilder(); + + sb.append("{ \"frames\": {\n"); + for (int i = 0; i < frames.length; i++) { + String json = gson.toJson(frames[i]); + sb.append(" \"" + frames[i].name + "\": ").append(json).append(",\n"); + } + sb.append(" },\n"); + String json = gson.toJson(meta); + sb.append("\"meta\":").append(json).append("\n}"); + + return sb.toString(); + } + + /** + * Frames class for Aseprite json structure. + */ + private static class Frames { + transient String name; + Map frame; + boolean rotated; + boolean trimmed; + Map spriteSourceSize; + Map sourceSize; + int duration; + + /** + * @param name name of frame + * @param frame x, y, w, h on the substruction of the sprite in the spritesheet. + * @param rotated is the frame rotated? + * @param trimmed is the frame trimmed? + * @param spriteSourceSize how the sprite is trimmed. + * @param sourceSize the original sprite size. + * @param duration the duration of the frame + */ + public Frames(String name, Map frame, boolean rotated, boolean trimmed, Map spriteSourceSize, Map sourceSize, int duration) { + this.name = name; + this.frame = frame; + this.rotated = rotated; + this.trimmed = trimmed; + this.spriteSourceSize = spriteSourceSize; + this.sourceSize = sourceSize; + this.duration = duration; + } + } + + /** + * Meta data class for Aseprite json structure. + */ + private static class Meta { + String app; + String version; + String image; + String format; + Map size; + String scale; + Layer[] layers; + + /** + * @param app the application the json format comes from, in this case Aseprite. + * @param version Version of application. + * @param image filename of spritesheet. + * @param format color format of spritesheet image. + * @param size Size of spritesheet. + * @param scale Scale of spritesheet. + * @param layers Layers of spritesheet. + */ + public Meta(String app, String version, String image, String format, Map size, String scale, Layer[] layers) { + this.app = app; + this.version = version; + this.image = image; + this.format = format; + this.size = size; + this.scale = scale; + this.layers = layers; + } + } + + /** + * Layer class for Aseprite json structure. + */ + private static class Layer { + String name; + int opacity; + String blendMode; + + /** + * @param name Name of layer. + * @param opacity Opacity level of layer. + * @param blendMode Blendmode of layer. + */ + public Layer(String name, int opacity, String blendMode) { + this.name = name; + this.opacity = opacity; + this.blendMode = blendMode; + } + + } +} From 865a105a41cf9699806e8b9e75004d73ff3bf94f Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 10:06:04 +0100 Subject: [PATCH 33/54] Update AsepriteHandlerTests.java Ran autoformat --- .../animation/AsepriteHandlerTests.java | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 3c337b4f5..becc5781f 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -16,82 +16,82 @@ import de.gurkenlabs.litiengine.resources.SpritesheetResource; -public class AsepriteHandlerTests { - - /** - * Tests that Aseprite animation import works as expected when given valid input. - */ - @Test - public void importAsepriteAnimationTest() { - try { - Animation animation = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json"); - assertEquals("Sprite-0001-sheet", animation.getName()); - assertEquals(300, animation.getTotalDuration()); - for(int keyFrameDuration : animation.getKeyFrameDurations()) - assertEquals(100, keyFrameDuration); - - Spritesheet spriteSheet = animation.getSpritesheet(); - assertEquals(32, spriteSheet.getSpriteHeight()); - assertEquals(32, spriteSheet.getSpriteWidth()); - assertEquals(3, spriteSheet.getTotalNumberOfSprites()); - assertEquals(1, spriteSheet.getRows()); - assertEquals(3, spriteSheet.getColumns()); - assertEquals(ImageFormat.PNG, spriteSheet.getImageFormat()); +import static org.junit.jupiter.api.Assertions.*; - BufferedImage image = spriteSheet.getImage(); - assertEquals(96, image.getWidth()); - assertEquals(32, image.getHeight()); - } - catch(FileNotFoundException e) { - fail(e.getMessage()); - } - catch(IOException e) { - fail(e.getMessage()); - } - catch(AsepriteHandler.ImportAnimationException e) { - fail(e.getMessage()); - } - } - /** - * Test that if AsepriteHandler.ImportAnimationException will be throwed if different frame dimensions are provided. - */ - @Test - public void ImportAnimationExceptionTest() { - - Throwable exception = assertThrows(ImportAnimationException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json")); - assertEquals("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions.", exception.getMessage()); - } - - /** - * Tests thrown FileNotFoundException when importing an Aseprite animation. - * - * 1.first, we test if FileNotFoundException would be throwed if .json file cannot be found. - * 2.then we test if FileNotFoundException would be throwed if spritesheet file cannot be found. - */ - @Test - public void FileNotFoundExceptionTest(){ - Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); - assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); - Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); - assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, which evaluates to: tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", exception_withoutSpriteSheet.getMessage()); - } - - /** - * Test that just create a json and prints in to standard output. - */ - @Test - public void exportAnimationTest() { - String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png"; - BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); - Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); - Animation animation = new Animation(spritesheet, false, false, 2,2,2); - int[] keyFrames = animation.getKeyFrameDurations(); - SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); - spritesheetResource.setKeyframes(keyFrames); - - AsepriteHandler aseprite = new AsepriteHandler(); - String result = aseprite.exportAnimation(spritesheetResource); - System.out.println(result); - } +public class AsepriteHandlerTests { + + /** + * Tests that Aseprite animation import works as expected when given valid input. + */ + @Test + public void importAsepriteAnimationTest() { + try { + Animation animation = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json"); + assertEquals("Sprite-0001-sheet", animation.getName()); + assertEquals(300, animation.getTotalDuration()); + for (int keyFrameDuration : animation.getKeyFrameDurations()) + assertEquals(100, keyFrameDuration); + + Spritesheet spriteSheet = animation.getSpritesheet(); + assertEquals(32, spriteSheet.getSpriteHeight()); + assertEquals(32, spriteSheet.getSpriteWidth()); + assertEquals(3, spriteSheet.getTotalNumberOfSprites()); + assertEquals(1, spriteSheet.getRows()); + assertEquals(3, spriteSheet.getColumns()); + assertEquals(ImageFormat.PNG, spriteSheet.getImageFormat()); + + BufferedImage image = spriteSheet.getImage(); + assertEquals(96, image.getWidth()); + assertEquals(32, image.getHeight()); + } catch (FileNotFoundException e) { + fail(e.getMessage()); + } catch (IOException e) { + fail(e.getMessage()); + } catch (AsepriteHandler.ImportAnimationException e) { + fail(e.getMessage()); + } + } + + /** + * Test that if AsepriteHandler.ImportAnimationException will be throwed if different frame dimensions are provided. + */ + @Test + public void ImportAnimationExceptionTest() { + + Throwable exception = assertThrows(ImportAnimationException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json")); + assertEquals("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions.", exception.getMessage()); + } + + /** + * Tests thrown FileNotFoundException when importing an Aseprite animation. + *

+ * 1.first, we test if FileNotFoundException would be throwed if .json file cannot be found. + * 2.then we test if FileNotFoundException would be throwed if spritesheet file cannot be found. + */ + @Test + public void FileNotFoundExceptionTest() { + Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); + assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); + Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); + assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, which evaluates to: tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", exception_withoutSpriteSheet.getMessage()); + } + + /** + * Test that just create a json and prints in to standard output. + */ + @Test + public void exportAnimationTest() { + String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png"; + BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); + Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); + Animation animation = new Animation(spritesheet, false, false, 2, 2, 2); + int[] keyFrames = animation.getKeyFrameDurations(); + SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); + spritesheetResource.setKeyframes(keyFrames); + + AsepriteHandler aseprite = new AsepriteHandler(); + String result = aseprite.exportAnimation(spritesheetResource); + System.out.println(result); + } } From 5f80679b77db54a3491ad3f76aa653a12adc4b27 Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Wed, 10 Mar 2021 13:17:46 +0100 Subject: [PATCH 34/54] Improve spritesheet file search for Aseprite import Now searches directory of .json too if the file given in .json metadata can't be found. Also, modifies affected test. --- .../graphics/animation/AsepriteHandler.java | 61 ++++++++++++++++--- .../animation/AsepriteHandlerTests.java | 2 +- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index e27e61a8a..4106a8e76 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -4,6 +4,8 @@ import java.io.FileReader; import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.awt.Dimension; import java.awt.Image; import java.awt.image.BufferedImage; @@ -11,6 +13,7 @@ import java.util.Map; import java.util.HashMap; import java.util.List; +import java.util.Arrays; import javax.imageio.ImageIO; import com.google.gson.Gson; @@ -43,7 +46,6 @@ public ImportAnimationException(String message) { /** * Imports an Aseprite animation (.json + sprite sheet). - * Note: searches for sprite sheet path through .json metadata, specifically 'image' element. This should be an absolute path in system. * * @param jsonPath path (including filename) to Aseprite JSON. * @@ -57,11 +59,11 @@ public static Animation importAnimation(String jsonPath) throws IOException, Fil throw new FileNotFoundException("FileNotFoundException: Could not find .json file " + jsonPath); } - String spriteSheetPath = getSpriteSheetPath(rootElement); - File spriteSheetFile = new File(spriteSheetPath); - if(!spriteSheetFile.exists()) { + File spriteSheetFile = null; + try { spriteSheetFile = getSpriteSheetFile(rootElement, jsonPath); } + catch(FileNotFoundException e) { throw new FileNotFoundException("FileNotFoundException: Could not find sprite sheet file. " + - "Expected location is 'image' in .json metadata, which evaluates to: " + spriteSheetPath); + "Expected location is 'image' in .json metadata, or same folder as .json file."); } Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); @@ -74,7 +76,7 @@ public static Animation importAnimation(String jsonPath) throws IOException, Fil } Spritesheet spriteSheet = new Spritesheet(image, - spriteSheetPath, + spriteSheetFile.getPath().toString(), (int)keyFrameDimensions.getWidth(), (int)keyFrameDimensions.getHeight()); @@ -100,6 +102,51 @@ private static JsonElement getRootJsonElement(String jsonPath) throws FileNotFou catch(FileNotFoundException e) { throw e; } } + /** + * Searches for sprite sheet path through .json metadata, or same folder as .json file. + * @param rootElement root element of JSON data. + * @param jsonPath path (including filename) to .json Aseprite file. + * + * @return sprite sheet file if it can be found, else an exception is thrown. + * */ + private static File getSpriteSheetFile(JsonElement rootElement, String jsonPath) throws FileNotFoundException { + + //try searching path supplied in .json data + JsonElement metaData = rootElement.getAsJsonObject().get("meta"); + String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); + + File spriteSheetFile = new File(spriteSheetPath); + + if(spriteSheetFile.exists()) + return spriteSheetFile; + + //try searching local directory + Path jsonFilePath = Paths.get(jsonPath); + String dirPath = jsonFilePath.getParent().toString(); + String fileName1 = jsonFilePath.getFileName().toString(); + String alternative1 = fileName1.substring(0, fileName1.lastIndexOf(".")); //same file name as .json + + Path spriteSheetFilePath = Paths.get(spriteSheetPath); + String fileName2 = spriteSheetFilePath.getFileName().toString(); + String alternative2 = fileName2.substring(0, fileName2.lastIndexOf(".")); //same file name as 'image' element + + List suffixes = Arrays.asList(".png", ".jpg", ".jpeg"); + for(String suffix : suffixes) { + + String alternativeFile1 = dirPath + "/" + alternative1 + suffix; + spriteSheetFile = new File(alternativeFile1); + if(spriteSheetFile.exists()) + return spriteSheetFile; + + String alternativeFile2 = dirPath + "/" + alternative2 + suffix; + spriteSheetFile = new File(alternativeFile2); + if(spriteSheetFile.exists()) + return spriteSheetFile; + } + + throw new FileNotFoundException(); + } + /** * @param rootElement root element of JSON data. * @@ -370,4 +417,4 @@ public Layer(String name, int opacity, String blendMode){ } } -} \ No newline at end of file +} diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 3c337b4f5..a330552c4 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -74,7 +74,7 @@ public void FileNotFoundExceptionTest(){ Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); - assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, which evaluates to: tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", exception_withoutSpriteSheet.getMessage()); + assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, or same folder as .json file.", exception_withoutSpriteSheet.getMessage()); } /** From 27942cc9b9e8b05b0df148f79c2146da5d00bbe2 Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 13:39:40 +0100 Subject: [PATCH 35/54] Merge Changes from Issue/321 --- .../graphics/animation/AsepriteHandler.java | 56 +++++++++++++++++-- .../animation/AsepriteHandlerTests.java | 2 +- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index bfebda2da..8434724e5 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -43,7 +43,6 @@ public ImportAnimationException(String message) { /** * Imports an Aseprite animation (.json + sprite sheet). - * Note: searches for sprite sheet path through .json metadata, specifically 'image' element. This should be an absolute path in system. * * @param jsonPath path (including filename) to Aseprite JSON. * @return Animation object represented by each key frame in Aseprite sprite sheet. @@ -57,11 +56,11 @@ public static Animation importAnimation(String jsonPath) throws IOException, Fil throw new FileNotFoundException("FileNotFoundException: Could not find .json file " + jsonPath); } - String spriteSheetPath = getSpriteSheetPath(rootElement); - File spriteSheetFile = new File(spriteSheetPath); - if (!spriteSheetFile.exists()) { + File spriteSheetFile = null; + try { spriteSheetFile = getSpriteSheetFile(rootElement, jsonPath); } + catch(FileNotFoundException e) { throw new FileNotFoundException("FileNotFoundException: Could not find sprite sheet file. " + - "Expected location is 'image' in .json metadata, which evaluates to: " + spriteSheetPath); + "Expected location is 'image' in .json metadata, or same folder as .json file."); } Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); @@ -75,7 +74,7 @@ public static Animation importAnimation(String jsonPath) throws IOException, Fil } Spritesheet spriteSheet = new Spritesheet(image, - spriteSheetPath, + spriteSheetFile.getPath().toString(), (int) keyFrameDimensions.getWidth(), (int) keyFrameDimensions.getHeight()); @@ -113,6 +112,51 @@ private static String getSpriteSheetPath(JsonElement rootElement) { return spriteSheetPath; } + /** + * Searches for sprite sheet path through .json metadata, or same folder as .json file. + * @param rootElement root element of JSON data. + * @param jsonPath path (including filename) to .json Aseprite file. + * + * @return sprite sheet file if it can be found, else an exception is thrown. + * */ + private static File getSpriteSheetFile(JsonElement rootElement, String jsonPath) throws FileNotFoundException { + + //try searching path supplied in .json data + JsonElement metaData = rootElement.getAsJsonObject().get("meta"); + String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); + + File spriteSheetFile = new File(spriteSheetPath); + + if(spriteSheetFile.exists()) + return spriteSheetFile; + + //try searching local directory + Path jsonFilePath = Paths.get(jsonPath); + String dirPath = jsonFilePath.getParent().toString(); + String fileName1 = jsonFilePath.getFileName().toString(); + String alternative1 = fileName1.substring(0, fileName1.lastIndexOf(".")); //same file name as .json + + Path spriteSheetFilePath = Paths.get(spriteSheetPath); + String fileName2 = spriteSheetFilePath.getFileName().toString(); + String alternative2 = fileName2.substring(0, fileName2.lastIndexOf(".")); //same file name as 'image' element + + List suffixes = Arrays.asList(".png", ".jpg", ".jpeg"); + for(String suffix : suffixes) { + + String alternativeFile1 = dirPath + "/" + alternative1 + suffix; + spriteSheetFile = new File(alternativeFile1); + if(spriteSheetFile.exists()) + return spriteSheetFile; + + String alternativeFile2 = dirPath + "/" + alternative2 + suffix; + spriteSheetFile = new File(alternativeFile2); + if(spriteSheetFile.exists()) + return spriteSheetFile; + } + + throw new FileNotFoundException(); + } + /** * @param rootElement root element of JSON data. * @return dimensions of first key frame. diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index becc5781f..c8a5f2ca6 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -74,7 +74,7 @@ public void FileNotFoundExceptionTest() { Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); - assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, which evaluates to: tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", exception_withoutSpriteSheet.getMessage()); + assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, or same folder as .json file.", exception_withoutSpriteSheet.getMessage()); } /** From 5597332103ce62090849cdabb165cda48ab6f20b Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 13:46:53 +0100 Subject: [PATCH 36/54] Update AsepriteHandler.java --- .../litiengine/graphics/animation/AsepriteHandler.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 8434724e5..2c01da6f3 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -12,6 +12,9 @@ import java.util.HashMap; import java.util.List; import javax.imageio.ImageIO; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; import com.google.gson.Gson; import com.google.gson.GsonBuilder; From bbf14578f9465a03f9bdae21a1b1d3f1b94fceef Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 14:55:18 +0100 Subject: [PATCH 37/54] Added caught exceptions catches the right exceptions and logs them --- utiliti/src/de/gurkenlabs/utiliti/components/Editor.java | 8 ++++---- .../src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java index 6567da823..74b839a59 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java +++ b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java @@ -516,10 +516,10 @@ public void processAnimation(File file) { } this.loadSpriteSheets(sprites, true); - } catch (IOException e) { - e.printStackTrace(); - } - } + } catch (AsepriteHandler.ImportAnimationException | IOException e) { + log.log(Level.SEVERE, e.getMessage(), e); + } + } public void importEmitters() { XmlImportDialog.importXml("Emitter", file -> { diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java index d7b3219ad..b8d26f867 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java @@ -486,7 +486,7 @@ private void exportSpritesheet() { break; } } - } catch (IOException e) { + } catch (AsepriteHandler.ExportAnimationException | IOException e) { log.log(Level.SEVERE, e.getMessage(), e); } } From 00842ccb8afa6fa03402cc4b1158d6c6d4c7e3cf Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 15:08:59 +0100 Subject: [PATCH 38/54] Fix formatting --- .../graphics/animation/AsepriteHandler.java | 691 +++++++++--------- .../animation/AsepriteHandlerTests.java | 148 ++-- .../gurkenlabs/utiliti/components/Editor.java | 48 +- .../utiliti/swing/menus/ResourcesMenu.java | 10 +- 4 files changed, 450 insertions(+), 447 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index dcea9e172..81a92200e 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -34,378 +34,381 @@ * Note: requires animation key frames to have same dimensions to support internal animation format. */ public class AsepriteHandler { - - /** - * Thrown to indicate error when importing Aseprite JSON format. - */ - public static class ImportAnimationException extends Error { - public ImportAnimationException(String message) { - super(message); - } - } - - /** - * Imports an Aseprite animation (.json + sprite sheet). - * - * @param jsonPath path (including filename) to Aseprite JSON. - * @return Animation object represented by each key frame in Aseprite sprite sheet. - */ - public static Animation importAnimation(String jsonPath) throws IOException, FileNotFoundException, AsepriteHandler.ImportAnimationException { - - JsonElement rootElement = null; - try { rootElement = getRootJsonElement(jsonPath); } - catch (FileNotFoundException e) { - throw new FileNotFoundException("FileNotFoundException: Could not find .json file " + jsonPath); - } - + + /** + * Thrown to indicate error when importing Aseprite JSON format. + */ + public static class ImportAnimationException extends Error { + public ImportAnimationException(String message) { + super(message); + } + } + + /** + * Imports an Aseprite animation (.json + sprite sheet). + * + * @param jsonPath path (including filename) to Aseprite JSON. + * @return Animation object represented by each key frame in Aseprite sprite sheet. + */ + public static Animation importAnimation(String jsonPath) throws IOException, FileNotFoundException, AsepriteHandler.ImportAnimationException { + + JsonElement rootElement = null; + try { + rootElement = getRootJsonElement(jsonPath); + } catch (FileNotFoundException e) { + throw new FileNotFoundException("FileNotFoundException: Could not find .json file " + jsonPath); + } + File spriteSheetFile = null; - try { spriteSheetFile = getSpriteSheetFile(rootElement, jsonPath); } - catch(FileNotFoundException e) { + try { + spriteSheetFile = getSpriteSheetFile(rootElement, jsonPath); + } catch (FileNotFoundException e) { throw new FileNotFoundException("FileNotFoundException: Could not find sprite sheet file. " + - "Expected location is 'image' in .json metadata, or same folder as .json file."); + "Expected location is 'image' in .json metadata, or same folder as .json file."); } - - Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); - if (areKeyFramesSameDimensions(rootElement, keyFrameDimensions)) { - - BufferedImage image = null; - try { image = ImageIO.read(spriteSheetFile); } - catch (IOException e) { - throw new IOException("IOException: Could not write sprite sheet data to BufferedImage object."); - } - - Spritesheet spriteSheet = new Spritesheet(image, - spriteSheetFile.getPath().toString(), - (int) keyFrameDimensions.getWidth(), - (int) keyFrameDimensions.getHeight()); - - return new Animation(spriteSheet, false, getKeyFrameDurations(rootElement)); - } - - throw new AsepriteHandler.ImportAnimationException("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions."); - } - - /** - * @param jsonPath path (including filename) to Aseprite .json file. - * @return root element of JSON data. - */ - private static JsonElement getRootJsonElement(String jsonPath) throws FileNotFoundException { - - File jsonFile = new File(jsonPath); - - try { - JsonElement rootElement = JsonParser.parseReader(new FileReader(jsonFile)); - return rootElement; - } catch (FileNotFoundException e) { - throw e; - } - } - - /** - * @param rootElement root element of JSON data. - * @return path (including filename) to animation sprite sheet. - */ - private static String getSpriteSheetPath(JsonElement rootElement) { - - JsonElement metaData = rootElement.getAsJsonObject().get("meta"); - String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); - - return spriteSheetPath; - } - + + Dimension keyFrameDimensions = getKeyFrameDimensions(rootElement); + if (areKeyFramesSameDimensions(rootElement, keyFrameDimensions)) { + + BufferedImage image = null; + try { + image = ImageIO.read(spriteSheetFile); + } catch (IOException e) { + throw new IOException("IOException: Could not write sprite sheet data to BufferedImage object."); + } + + Spritesheet spriteSheet = new Spritesheet(image, + spriteSheetFile.getPath().toString(), + (int) keyFrameDimensions.getWidth(), + (int) keyFrameDimensions.getHeight()); + + return new Animation(spriteSheet, false, getKeyFrameDurations(rootElement)); + } + + throw new AsepriteHandler.ImportAnimationException("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions."); + } + + /** + * @param jsonPath path (including filename) to Aseprite .json file. + * @return root element of JSON data. + */ + private static JsonElement getRootJsonElement(String jsonPath) throws FileNotFoundException { + + File jsonFile = new File(jsonPath); + + try { + JsonElement rootElement = JsonParser.parseReader(new FileReader(jsonFile)); + return rootElement; + } catch (FileNotFoundException e) { + throw e; + } + } + /** - * Searches for sprite sheet path through .json metadata and same folder as .json file. * @param rootElement root element of JSON data. - * @param jsonPath path (including filename) to .json Aseprite file. + * @return path (including filename) to animation sprite sheet. + */ + private static String getSpriteSheetPath(JsonElement rootElement) { + + JsonElement metaData = rootElement.getAsJsonObject().get("meta"); + String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); + + return spriteSheetPath; + } + + /** + * Searches for sprite sheet path through .json metadata and same folder as .json file. * + * @param rootElement root element of JSON data. + * @param jsonPath path (including filename) to .json Aseprite file. * @return sprite sheet file if it can be found, else an exception is thrown. - * */ + */ private static File getSpriteSheetFile(JsonElement rootElement, String jsonPath) throws FileNotFoundException { - + //try searching path supplied in .json data JsonElement metaData = rootElement.getAsJsonObject().get("meta"); String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); - + File spriteSheetFile = new File(spriteSheetPath); - - if(spriteSheetFile.exists()) + + if (spriteSheetFile.exists()) return spriteSheetFile; - + //try searching local directory Path jsonFilePath = Paths.get(jsonPath); String dirPath = jsonFilePath.getParent().toString(); String fileName1 = jsonFilePath.getFileName().toString(); String alternative1 = fileName1.substring(0, fileName1.lastIndexOf(".")); //same file name as .json - + Path spriteSheetFilePath = Paths.get(spriteSheetPath); String fileName2 = spriteSheetFilePath.getFileName().toString(); String alternative2 = fileName2.substring(0, fileName2.lastIndexOf(".")); //same file name as 'image' element - + List suffixes = Arrays.asList(".png", ".jpg", ".jpeg"); - for(String suffix : suffixes) { - + for (String suffix : suffixes) { + String alternativeFile1 = dirPath + "/" + alternative1 + suffix; spriteSheetFile = new File(alternativeFile1); - if(spriteSheetFile.exists()) + if (spriteSheetFile.exists()) return spriteSheetFile; - + String alternativeFile2 = dirPath + "/" + alternative2 + suffix; spriteSheetFile = new File(alternativeFile2); - if(spriteSheetFile.exists()) + if (spriteSheetFile.exists()) return spriteSheetFile; } - + throw new FileNotFoundException(); } - - /** - * @param rootElement root element of JSON data. - * @return dimensions of first key frame. - */ - private static Dimension getKeyFrameDimensions(JsonElement rootElement) { - - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - - JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); - JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); - - int frameWidth = frameDimensions.get("w").getAsInt(); - int frameHeight = frameDimensions.get("h").getAsInt(); - - return new Dimension(frameWidth, frameHeight); - } - - /** - * @param rootElement root element of JSON data. - * @param expected expected dimensions of each key frame. - * @return true if key frames have same duration. - */ - private static boolean areKeyFramesSameDimensions(JsonElement rootElement, Dimension expected) { - - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - - for (Map.Entry entry : frames.getAsJsonObject().entrySet()) { - JsonObject frameObject = entry.getValue().getAsJsonObject(); - JsonObject frameDimensions = frameObject.get("sourceSize").getAsJsonObject(); - - int frameWidth = frameDimensions.get("w").getAsInt(); - int frameHeight = frameDimensions.get("h").getAsInt(); - - if (frameWidth != expected.getWidth() || frameHeight != expected.getHeight()) - return false; - } - - return true; - } - - /** - * @param rootElement root element of JSON data. - * @return integer array representing duration of each key frame. - */ - public static int[] getKeyFrameDurations(JsonElement rootElement) { - - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - - Set> keyFrameSet = frames.getAsJsonObject().entrySet(); - - int[] keyFrameDurations = new int[keyFrameSet.size()]; - - int frameIndex = 0; - for (Map.Entry entry : keyFrameSet) { - JsonObject frameObject = entry.getValue().getAsJsonObject(); - int frameDuration = frameObject.get("duration").getAsInt(); - keyFrameDurations[frameIndex++] = frameDuration; - } - - return keyFrameDurations; - } - - /** - * Error that is thrown by the export class - */ - public static class ExportAnimationException extends Error { - public ExportAnimationException(String message) { - super(message); - } - } - - /** - * Creates the json representation of an animation object and returns it. - * This is the public accesible function and can/should be changed to fit into the UI. - * - * @param spritesheetResource the animation object to export - */ - public static String exportAnimation(SpritesheetResource spritesheetResource) { - String json = createJson(spritesheetResource); - return json; - } - - /** - * Creates the json representation of an animation object and returns it as a string. - * - * @param spritesheetResource spritesheetResource object to export as json. - * @return the json as a string. - */ - private static String createJson(SpritesheetResource spritesheetResource) { - Spritesheet spritesheet = Resources.spritesheets().load(spritesheetResource); - assert spritesheet != null; - int[] keyframes = Resources.spritesheets().getCustomKeyFrameDurations(spritesheet); - Frames[] frames = new Frames[keyframes.length]; - - if (frames.length != spritesheet.getTotalNumberOfSprites()) { - throw new ExportAnimationException("Different dimensions of keyframes and sprites in spritesheet"); - } - - // Build the frames object in the json - int numCol = spritesheet.getColumns(); - int numRows = spritesheet.getRows(); - int frameWidth = spritesheet.getSpriteWidth(); - int frameHeight = spritesheet.getSpriteHeight(); - - for (int i = 0; i < numRows; i++) { - for (int j = 0; j < numCol; j++) { - final int row = i; - final int col = j; - Map frame = new HashMap<>() {{ - put("x", (0 + col * frameWidth)); - put("y", (0 + row * frameHeight)); - put("w", frameWidth); - put("h", frameHeight); - }}; - Map spriteSourceSize = new HashMap<>() {{ - put("x", 0); - put("y", 0); - put("w", frameWidth); - put("h", frameHeight); - }}; - Map sourceSize = new HashMap<>() {{ - put("w", frameWidth); - put("h", frameHeight); - }}; - int duration = keyframes[i + j]; - String index = String.valueOf(i + j); - frames[i + j] = new Frames("frame " + index, - frame, - false, - false, - spriteSourceSize, - sourceSize, - duration); - } - } - - // Build the meta object in the json - int spritesheetWidth = frameWidth * numCol; - int spritesheetHeight = frameHeight * numRows; - Map size = new HashMap<>() {{ - put("w", spritesheetWidth); - put("h", spritesheetHeight); - }}; - String spritesheetName = spritesheet.getName(); - Layer[] layers = {new Layer("Layer", 255, "normal")}; - Meta meta = new Meta("http://www.aseprite.org/", - "1.2.16.3-x64", - spritesheetName, - "RGBA8888", size, "1", layers); - - // Create the json as string - Gson gson = new GsonBuilder().setPrettyPrinting().create(); - StringBuilder sb = new StringBuilder(); - - sb.append("{ \"frames\": {\n"); - for (int i = 0; i < frames.length; i++) { - String json = gson.toJson(frames[i]); - sb.append(" \"" + frames[i].name + "\": ").append(json).append(",\n"); - } - sb.append(" },\n"); - String json = gson.toJson(meta); - sb.append("\"meta\":").append(json).append("\n}"); - - return sb.toString(); - } - - /** - * Frames class for Aseprite json structure. - */ - private static class Frames { - transient String name; - Map frame; - boolean rotated; - boolean trimmed; - Map spriteSourceSize; - Map sourceSize; - int duration; - - /** - * @param name name of frame - * @param frame x, y, w, h on the substruction of the sprite in the spritesheet. - * @param rotated is the frame rotated? - * @param trimmed is the frame trimmed? - * @param spriteSourceSize how the sprite is trimmed. - * @param sourceSize the original sprite size. - * @param duration the duration of the frame - */ - public Frames(String name, Map frame, boolean rotated, boolean trimmed, Map spriteSourceSize, Map sourceSize, int duration) { - this.name = name; - this.frame = frame; - this.rotated = rotated; - this.trimmed = trimmed; - this.spriteSourceSize = spriteSourceSize; - this.sourceSize = sourceSize; - this.duration = duration; - } - } - - /** - * Meta data class for Aseprite json structure. - */ - private static class Meta { - String app; - String version; - String image; - String format; - Map size; - String scale; - Layer[] layers; - - /** - * @param app the application the json format comes from, in this case Aseprite. - * @param version Version of application. - * @param image filename of spritesheet. - * @param format color format of spritesheet image. - * @param size Size of spritesheet. - * @param scale Scale of spritesheet. - * @param layers Layers of spritesheet. - */ - public Meta(String app, String version, String image, String format, Map size, String scale, Layer[] layers) { - this.app = app; - this.version = version; - this.image = image; - this.format = format; - this.size = size; - this.scale = scale; - this.layers = layers; - } - } - - /** - * Layer class for Aseprite json structure. - */ - private static class Layer { - String name; - int opacity; - String blendMode; - - /** - * @param name Name of layer. - * @param opacity Opacity level of layer. - * @param blendMode Blendmode of layer. - */ - public Layer(String name, int opacity, String blendMode) { - this.name = name; - this.opacity = opacity; - this.blendMode = blendMode; - } - - } -} \ No newline at end of file + + /** + * @param rootElement root element of JSON data. + * @return dimensions of first key frame. + */ + private static Dimension getKeyFrameDimensions(JsonElement rootElement) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); + JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + + return new Dimension(frameWidth, frameHeight); + } + + /** + * @param rootElement root element of JSON data. + * @param expected expected dimensions of each key frame. + * @return true if key frames have same duration. + */ + private static boolean areKeyFramesSameDimensions(JsonElement rootElement, Dimension expected) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + for (Map.Entry entry : frames.getAsJsonObject().entrySet()) { + JsonObject frameObject = entry.getValue().getAsJsonObject(); + JsonObject frameDimensions = frameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + + if (frameWidth != expected.getWidth() || frameHeight != expected.getHeight()) + return false; + } + + return true; + } + + /** + * @param rootElement root element of JSON data. + * @return integer array representing duration of each key frame. + */ + public static int[] getKeyFrameDurations(JsonElement rootElement) { + + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + + Set> keyFrameSet = frames.getAsJsonObject().entrySet(); + + int[] keyFrameDurations = new int[keyFrameSet.size()]; + + int frameIndex = 0; + for (Map.Entry entry : keyFrameSet) { + JsonObject frameObject = entry.getValue().getAsJsonObject(); + int frameDuration = frameObject.get("duration").getAsInt(); + keyFrameDurations[frameIndex++] = frameDuration; + } + + return keyFrameDurations; + } + + /** + * Error that is thrown by the export class + */ + public static class ExportAnimationException extends Error { + public ExportAnimationException(String message) { + super(message); + } + } + + /** + * Creates the json representation of an animation object and returns it. + * This is the public accesible function and can/should be changed to fit into the UI. + * + * @param spritesheetResource the animation object to export + */ + public static String exportAnimation(SpritesheetResource spritesheetResource) { + String json = createJson(spritesheetResource); + return json; + } + + /** + * Creates the json representation of an animation object and returns it as a string. + * + * @param spritesheetResource spritesheetResource object to export as json. + * @return the json as a string. + */ + private static String createJson(SpritesheetResource spritesheetResource) { + Spritesheet spritesheet = Resources.spritesheets().load(spritesheetResource); + assert spritesheet != null; + int[] keyframes = Resources.spritesheets().getCustomKeyFrameDurations(spritesheet); + Frames[] frames = new Frames[keyframes.length]; + + if (frames.length != spritesheet.getTotalNumberOfSprites()) { + throw new ExportAnimationException("Different dimensions of keyframes and sprites in spritesheet"); + } + + // Build the frames object in the json + int numCol = spritesheet.getColumns(); + int numRows = spritesheet.getRows(); + int frameWidth = spritesheet.getSpriteWidth(); + int frameHeight = spritesheet.getSpriteHeight(); + + for (int i = 0; i < numRows; i++) { + for (int j = 0; j < numCol; j++) { + final int row = i; + final int col = j; + Map frame = new HashMap<>() {{ + put("x", (0 + col * frameWidth)); + put("y", (0 + row * frameHeight)); + put("w", frameWidth); + put("h", frameHeight); + }}; + Map spriteSourceSize = new HashMap<>() {{ + put("x", 0); + put("y", 0); + put("w", frameWidth); + put("h", frameHeight); + }}; + Map sourceSize = new HashMap<>() {{ + put("w", frameWidth); + put("h", frameHeight); + }}; + int duration = keyframes[i + j]; + String index = String.valueOf(i + j); + frames[i + j] = new Frames("frame " + index, + frame, + false, + false, + spriteSourceSize, + sourceSize, + duration); + } + } + + // Build the meta object in the json + int spritesheetWidth = frameWidth * numCol; + int spritesheetHeight = frameHeight * numRows; + Map size = new HashMap<>() {{ + put("w", spritesheetWidth); + put("h", spritesheetHeight); + }}; + String spritesheetName = spritesheet.getName(); + Layer[] layers = {new Layer("Layer", 255, "normal")}; + Meta meta = new Meta("http://www.aseprite.org/", + "1.2.16.3-x64", + spritesheetName, + "RGBA8888", size, "1", layers); + + // Create the json as string + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + StringBuilder sb = new StringBuilder(); + + sb.append("{ \"frames\": {\n"); + for (int i = 0; i < frames.length; i++) { + String json = gson.toJson(frames[i]); + sb.append(" \"" + frames[i].name + "\": ").append(json).append(",\n"); + } + sb.append(" },\n"); + String json = gson.toJson(meta); + sb.append("\"meta\":").append(json).append("\n}"); + + return sb.toString(); + } + + /** + * Frames class for Aseprite json structure. + */ + private static class Frames { + transient String name; + Map frame; + boolean rotated; + boolean trimmed; + Map spriteSourceSize; + Map sourceSize; + int duration; + + /** + * @param name name of frame + * @param frame x, y, w, h on the substruction of the sprite in the spritesheet. + * @param rotated is the frame rotated? + * @param trimmed is the frame trimmed? + * @param spriteSourceSize how the sprite is trimmed. + * @param sourceSize the original sprite size. + * @param duration the duration of the frame + */ + public Frames(String name, Map frame, boolean rotated, boolean trimmed, Map spriteSourceSize, Map sourceSize, int duration) { + this.name = name; + this.frame = frame; + this.rotated = rotated; + this.trimmed = trimmed; + this.spriteSourceSize = spriteSourceSize; + this.sourceSize = sourceSize; + this.duration = duration; + } + } + + /** + * Meta data class for Aseprite json structure. + */ + private static class Meta { + String app; + String version; + String image; + String format; + Map size; + String scale; + Layer[] layers; + + /** + * @param app the application the json format comes from, in this case Aseprite. + * @param version Version of application. + * @param image filename of spritesheet. + * @param format color format of spritesheet image. + * @param size Size of spritesheet. + * @param scale Scale of spritesheet. + * @param layers Layers of spritesheet. + */ + public Meta(String app, String version, String image, String format, Map size, String scale, Layer[] layers) { + this.app = app; + this.version = version; + this.image = image; + this.format = format; + this.size = size; + this.scale = scale; + this.layers = layers; + } + } + + /** + * Layer class for Aseprite json structure. + */ + private static class Layer { + String name; + int opacity; + String blendMode; + + /** + * @param name Name of layer. + * @param opacity Opacity level of layer. + * @param blendMode Blendmode of layer. + */ + public Layer(String name, int opacity, String blendMode) { + this.name = name; + this.opacity = opacity; + this.blendMode = blendMode; + } + + } +} diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 766b7b04f..0961fb48c 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -18,78 +18,78 @@ import static org.junit.jupiter.api.Assertions.*; public class AsepriteHandlerTests { - - /** - * Tests that Aseprite animation import works as expected when given valid input. - */ - @Test - public void importAsepriteAnimationTest() { - try { - Animation animation = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json"); - assertEquals("Sprite-0001-sheet", animation.getName()); - assertEquals(300, animation.getTotalDuration()); - for (int keyFrameDuration : animation.getKeyFrameDurations()) - assertEquals(100, keyFrameDuration); - - Spritesheet spriteSheet = animation.getSpritesheet(); - assertEquals(32, spriteSheet.getSpriteHeight()); - assertEquals(32, spriteSheet.getSpriteWidth()); - assertEquals(3, spriteSheet.getTotalNumberOfSprites()); - assertEquals(1, spriteSheet.getRows()); - assertEquals(3, spriteSheet.getColumns()); - assertEquals(ImageFormat.PNG, spriteSheet.getImageFormat()); - - BufferedImage image = spriteSheet.getImage(); - assertEquals(96, image.getWidth()); - assertEquals(32, image.getHeight()); - } catch (FileNotFoundException e) { - fail(e.getMessage()); - } catch (IOException e) { - fail(e.getMessage()); - } catch (AsepriteHandler.ImportAnimationException e) { - fail(e.getMessage()); - } - } - - /** - * Test that if AsepriteHandler.ImportAnimationException will be throwed if different frame dimensions are provided. - */ - @Test - public void ImportAnimationExceptionTest() { - - Throwable exception = assertThrows(ImportAnimationException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json")); - assertEquals("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions.", exception.getMessage()); - } - - /** - * Tests thrown FileNotFoundException when importing an Aseprite animation. - *

- * 1.first, we test if FileNotFoundException would be throwed if .json file cannot be found. - * 2.then we test if FileNotFoundException would be throwed if spritesheet file cannot be found. - */ - @Test - public void FileNotFoundExceptionTest() { - Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); - assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); - Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); - assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, or same folder as .json file.", exception_withoutSpriteSheet.getMessage()); - } - - /** - * Test that just create a json and prints in to standard output. - */ - @Test - public void exportAnimationTest() { - String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png"; - BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); - Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); - Animation animation = new Animation(spritesheet, false, false, 2, 2, 2); - int[] keyFrames = animation.getKeyFrameDurations(); - SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); - spritesheetResource.setKeyframes(keyFrames); - - AsepriteHandler aseprite = new AsepriteHandler(); - String result = aseprite.exportAnimation(spritesheetResource); - System.out.println(result); - } + + /** + * Tests that Aseprite animation import works as expected when given valid input. + */ + @Test + public void importAsepriteAnimationTest() { + try { + Animation animation = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json"); + assertEquals("Sprite-0001-sheet", animation.getName()); + assertEquals(300, animation.getTotalDuration()); + for (int keyFrameDuration : animation.getKeyFrameDurations()) + assertEquals(100, keyFrameDuration); + + Spritesheet spriteSheet = animation.getSpritesheet(); + assertEquals(32, spriteSheet.getSpriteHeight()); + assertEquals(32, spriteSheet.getSpriteWidth()); + assertEquals(3, spriteSheet.getTotalNumberOfSprites()); + assertEquals(1, spriteSheet.getRows()); + assertEquals(3, spriteSheet.getColumns()); + assertEquals(ImageFormat.PNG, spriteSheet.getImageFormat()); + + BufferedImage image = spriteSheet.getImage(); + assertEquals(96, image.getWidth()); + assertEquals(32, image.getHeight()); + } catch (FileNotFoundException e) { + fail(e.getMessage()); + } catch (IOException e) { + fail(e.getMessage()); + } catch (AsepriteHandler.ImportAnimationException e) { + fail(e.getMessage()); + } + } + + /** + * Test that if AsepriteHandler.ImportAnimationException will be throwed if different frame dimensions are provided. + */ + @Test + public void ImportAnimationExceptionTest() { + + Throwable exception = assertThrows(ImportAnimationException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json")); + assertEquals("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions.", exception.getMessage()); + } + + /** + * Tests thrown FileNotFoundException when importing an Aseprite animation. + *

+ * 1.first, we test if FileNotFoundException would be throwed if .json file cannot be found. + * 2.then we test if FileNotFoundException would be throwed if spritesheet file cannot be found. + */ + @Test + public void FileNotFoundExceptionTest() { + Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); + assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); + Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); + assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, or same folder as .json file.", exception_withoutSpriteSheet.getMessage()); + } + + /** + * Test that just create a json and prints in to standard output. + */ + @Test + public void exportAnimationTest() { + String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png"; + BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); + Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); + Animation animation = new Animation(spritesheet, false, false, 2, 2, 2); + int[] keyFrames = animation.getKeyFrameDurations(); + SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); + spritesheetResource.setKeyframes(keyFrames); + + AsepriteHandler aseprite = new AsepriteHandler(); + String result = aseprite.exportAnimation(spritesheetResource); + System.out.println(result); + } } diff --git a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java index 74b839a59..47442d83d 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java +++ b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java @@ -384,10 +384,10 @@ public void importSpriteSheets() { } public void importAnimation() { - if (EditorFileChooser.showFileDialog(ANIMATION_FILE_NAME, Resources.strings().get(IMPORT_DIALOGUE, ANIMATION_FILE_NAME), false, "json") == JFileChooser.APPROVE_OPTION) { - this.processAnimation(EditorFileChooser.instance().getSelectedFile()); - } - } + if (EditorFileChooser.showFileDialog(ANIMATION_FILE_NAME, Resources.strings().get(IMPORT_DIALOGUE, ANIMATION_FILE_NAME), false, "json") == JFileChooser.APPROVE_OPTION) { + this.processAnimation(EditorFileChooser.instance().getSelectedFile()); + } + } public void importSounds() { if (EditorFileChooser.showFileDialog(AUDIO_FILE_NAME, Resources.strings().get(IMPORT_DIALOGUE, AUDIO_FILE_NAME), true, SoundFormat.getAllExtensions()) == JFileChooser.APPROVE_OPTION) { @@ -497,26 +497,26 @@ private void processSpritesheets(SpritesheetImportPanel spritePanel) { this.loadSpriteSheets(sprites, true); } - /** - * Loads an animation (spritesheet with keyframes) in to the editor - * @param file - a json file, encoded by the asesprite export standard - */ - public void processAnimation(File file) { - try { - Animation animation = AsepriteHandler.importAnimation(file.getAbsolutePath()); - int[] keyFrames = animation.getKeyFrameDurations(); - SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); - spritesheetResource.setKeyframes(keyFrames); - Collection sprites = new ArrayList<>(Collections.singleton(spritesheetResource)); - for (SpritesheetResource info : sprites) { - Resources.spritesheets().getAll().removeIf(x -> x.getName().equals(info.getName() + "-preview")); - this.getGameFile().getSpriteSheets().removeIf(x -> x.getName().equals(info.getName())); - this.getGameFile().getSpriteSheets().add(info); - log.log(Level.INFO, "imported spritesheet {0}", new Object[]{info.getName()}); - } - this.loadSpriteSheets(sprites, true); - - } catch (AsepriteHandler.ImportAnimationException | IOException e) { + /** + * Loads an animation (spritesheet with keyframes) in to the editor + * @param file - a json file, encoded by the asesprite export standard + */ + public void processAnimation(File file) { + try { + Animation animation = AsepriteHandler.importAnimation(file.getAbsolutePath()); + int[] keyFrames = animation.getKeyFrameDurations(); + SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); + spritesheetResource.setKeyframes(keyFrames); + Collection sprites = new ArrayList<>(Collections.singleton(spritesheetResource)); + for (SpritesheetResource info : sprites) { + Resources.spritesheets().getAll().removeIf(x -> x.getName().equals(info.getName() + "-preview")); + this.getGameFile().getSpriteSheets().removeIf(x -> x.getName().equals(info.getName())); + this.getGameFile().getSpriteSheets().add(info); + log.log(Level.INFO, "imported spritesheet {0}", new Object[]{info.getName()}); + } + this.loadSpriteSheets(sprites, true); + + } catch (AsepriteHandler.ImportAnimationException | IOException e) { log.log(Level.SEVERE, e.getMessage(), e); } } diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java b/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java index 1531483ae..adfa1173a 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/menus/ResourcesMenu.java @@ -54,8 +54,8 @@ public ResourcesMenu() { exportSpriteSheets.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK)); exportSpriteSheets.addActionListener(a -> Editor.instance().exportSpriteSheets()); - JMenuItem importAnimation = new JMenuItem(Resources.strings().get("menu_assets_importAnimation")); - importAnimation.addActionListener(a -> Editor.instance().importAnimation()); + JMenuItem importAnimation = new JMenuItem(Resources.strings().get("menu_assets_importAnimation")); + importAnimation.addActionListener(a -> Editor.instance().importAnimation()); importAnimation.setEnabled(false); Editor.instance().onLoaded(() -> { @@ -67,7 +67,7 @@ public ResourcesMenu() { importTilesets.setEnabled(Editor.instance().getCurrentResourceFile() != null); importSounds.setEnabled(Editor.instance().getCurrentResourceFile() != null); exportSpriteSheets.setEnabled(Editor.instance().getCurrentResourceFile() != null); - importAnimation.setEnabled(Editor.instance().getCurrentResourceFile() != null); + importAnimation.setEnabled(Editor.instance().getCurrentResourceFile() != null); }); this.add(importSprite); @@ -77,8 +77,8 @@ public ResourcesMenu() { this.add(importBlueprints); this.add(importTilesets); this.add(importSounds); - this.add(importAnimation); - this.addSeparator(); + this.add(importAnimation); + this.addSeparator(); this.add(exportSpriteSheets); this.add(compress); } From c8a0baed97f8a1387b5c53b8932f85afa229e52e Mon Sep 17 00:00:00 2001 From: HannesSundin Date: Wed, 10 Mar 2021 15:11:22 +0100 Subject: [PATCH 39/54] Fix format in AssetPanelItem.exportspriteSheet --- .../utiliti/swing/AssetPanelItem.java | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java index b8d26f867..8ceb6e59b 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java @@ -445,47 +445,47 @@ private void exportSpritesheet() { chooser.setFileSelectionMode(JFileChooser.FILES_ONLY); chooser.setDialogType(JFileChooser.SAVE_DIALOG); chooser.setDialogTitle("Export Spritesheet"); - switch (answer) { - case 0: { - XmlExportDialog.export(spriteSheetInfo, "Spritesheet", spriteSheetInfo.getName()); - break; - } - case 1: { - FileFilter filter = new FileNameExtensionFilter(format.toString() + " - Image", format.toString()); - chooser.setFileFilter(filter); - chooser.addChoosableFileFilter(filter); - chooser.setSelectedFile(new File(spriteSheetInfo.getName() + format.toFileExtension())); - - int result = chooser.showSaveDialog(Game.window().getRenderComponent()); - if (result == JFileChooser.APPROVE_OPTION) { - ImageSerializer.saveImage(chooser.getSelectedFile().toString(), sprite.getImage(), format); - log.log(Level.INFO, "exported spritesheet {0} to {1}", new Object[]{spriteSheetInfo.getName(), chooser.getSelectedFile()}); - } - break; - } - case 2: { - FileFilter filter = new FileNameExtensionFilter(".json" + " - " + "Spritesheet" + " JSON", "json"); - chooser.setFileFilter(filter); - chooser.addChoosableFileFilter(filter); - chooser.setSelectedFile(new File(spriteSheetInfo.getName() + "." + "json")); - - int result = chooser.showSaveDialog(Game.window().getRenderComponent()); - if (result == JFileChooser.APPROVE_OPTION) { - String fileNameWithExtension = chooser.getSelectedFile().toString(); - if (!fileNameWithExtension.endsWith(".json")) { - fileNameWithExtension += ".json"; - } - String json = AsepriteHandler.exportAnimation(spriteSheetInfo); - try (Writer writer = new FileWriter(fileNameWithExtension)) { - writer.write(json); - log.log(Level.INFO, "Exported {0} {1} to {2}", new Object[]{"Spritesheet", spriteSheetInfo.getName(), fileNameWithExtension}); - } catch (IOException e) { - e.printStackTrace(); - } - } - break; - } - } + switch (answer) { + case 0: { + XmlExportDialog.export(spriteSheetInfo, "Spritesheet", spriteSheetInfo.getName()); + break; + } + case 1: { + FileFilter filter = new FileNameExtensionFilter(format.toString() + " - Image", format.toString()); + chooser.setFileFilter(filter); + chooser.addChoosableFileFilter(filter); + chooser.setSelectedFile(new File(spriteSheetInfo.getName() + format.toFileExtension())); + + int result = chooser.showSaveDialog(Game.window().getRenderComponent()); + if (result == JFileChooser.APPROVE_OPTION) { + ImageSerializer.saveImage(chooser.getSelectedFile().toString(), sprite.getImage(), format); + log.log(Level.INFO, "exported spritesheet {0} to {1}", new Object[]{spriteSheetInfo.getName(), chooser.getSelectedFile()}); + } + break; + } + case 2: { + FileFilter filter = new FileNameExtensionFilter(".json" + " - " + "Spritesheet" + " JSON", "json"); + chooser.setFileFilter(filter); + chooser.addChoosableFileFilter(filter); + chooser.setSelectedFile(new File(spriteSheetInfo.getName() + "." + "json")); + + int result = chooser.showSaveDialog(Game.window().getRenderComponent()); + if (result == JFileChooser.APPROVE_OPTION) { + String fileNameWithExtension = chooser.getSelectedFile().toString(); + if (!fileNameWithExtension.endsWith(".json")) { + fileNameWithExtension += ".json"; + } + String json = AsepriteHandler.exportAnimation(spriteSheetInfo); + try (Writer writer = new FileWriter(fileNameWithExtension)) { + writer.write(json); + log.log(Level.INFO, "Exported {0} {1} to {2}", new Object[]{"Spritesheet", spriteSheetInfo.getName(), fileNameWithExtension}); + } catch (IOException e) { + e.printStackTrace(); + } + } + break; + } + } } catch (AsepriteHandler.ExportAnimationException | IOException e) { log.log(Level.SEVERE, e.getMessage(), e); } From ad99750231f32f84d30aac2bfd640ba6ff9b3342 Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Wed, 10 Mar 2021 15:48:49 +0100 Subject: [PATCH 40/54] Fix formatting --- utiliti/src/de/gurkenlabs/utiliti/components/Editor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java index 47442d83d..d5c014810 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java +++ b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java @@ -79,7 +79,7 @@ public class Editor extends Screen { private static final String TEXTUREATLAS_FILE_NAME = "Texture Atlas XML (generic)"; private static final String IMPORT_DIALOGUE = "import_something"; - private static final String ANIMATION_FILE_NAME = "Animation file"; + private static final String ANIMATION_FILE_NAME = "Animation file"; private static Editor instance; private static UserPreferences preferences; From 692f4229e4272280819e222c58098aeec23b7d21 Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Wed, 10 Mar 2021 16:33:11 +0100 Subject: [PATCH 41/54] Modify spritesheet searching in Aseprite import Removes unwanted possible spritesheet paths. Now searches 'image' element in .json data, and same directory as .json for filename of 'image' element and same name as .json with appropriate suffix. --- .../graphics/animation/AsepriteHandler.java | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 81a92200e..2e4d32577 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -133,31 +133,29 @@ private static File getSpriteSheetFile(JsonElement rootElement, String jsonPath) if (spriteSheetFile.exists()) return spriteSheetFile; - + //try searching local directory Path jsonFilePath = Paths.get(jsonPath); String dirPath = jsonFilePath.getParent().toString(); - String fileName1 = jsonFilePath.getFileName().toString(); - String alternative1 = fileName1.substring(0, fileName1.lastIndexOf(".")); //same file name as .json - - Path spriteSheetFilePath = Paths.get(spriteSheetPath); - String fileName2 = spriteSheetFilePath.getFileName().toString(); - String alternative2 = fileName2.substring(0, fileName2.lastIndexOf(".")); //same file name as 'image' element - - List suffixes = Arrays.asList(".png", ".jpg", ".jpeg"); - for (String suffix : suffixes) { - - String alternativeFile1 = dirPath + "/" + alternative1 + suffix; - spriteSheetFile = new File(alternativeFile1); - if (spriteSheetFile.exists()) - return spriteSheetFile; - - String alternativeFile2 = dirPath + "/" + alternative2 + suffix; - spriteSheetFile = new File(alternativeFile2); - if (spriteSheetFile.exists()) - return spriteSheetFile; - } - + + //same name as filename in 'image' element + String fileNameSheet = Paths.get(spriteSheetPath).getFileName().toString(); //name of spritesheet + String alternativePath1 = dirPath + "/" + fileNameSheet; + + spriteSheetFile = new File(alternativePath1); + if(spriteSheetFile.exists()) + return spriteSheetFile; + + //same name as .json file + String fileNameJson = jsonFilePath.getFileName().toString(); + String trimmedJsonName = fileNameJson.substring(0, fileNameJson.indexOf(".")); //without suffix + String sheetSuffix = fileNameSheet.substring(fileNameSheet.indexOf("."), fileNameSheet.length()); + String alternativePath2 = dirPath + "/" + trimmedJsonName + sheetSuffix; + + spriteSheetFile = new File(alternativePath2); + if(spriteSheetFile.exists()) + return spriteSheetFile; + throw new FileNotFoundException(); } From 8fb5d37a6356502b95ec1ec5e41658be1d3f09fb Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Wed, 10 Mar 2021 16:36:07 +0100 Subject: [PATCH 42/54] Remove unused method --- .../graphics/animation/AsepriteHandler.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 2e4d32577..6631eb174 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -104,18 +104,6 @@ private static JsonElement getRootJsonElement(String jsonPath) throws FileNotFou } } - /** - * @param rootElement root element of JSON data. - * @return path (including filename) to animation sprite sheet. - */ - private static String getSpriteSheetPath(JsonElement rootElement) { - - JsonElement metaData = rootElement.getAsJsonObject().get("meta"); - String spriteSheetPath = metaData.getAsJsonObject().get("image").getAsString(); - - return spriteSheetPath; - } - /** * Searches for sprite sheet path through .json metadata and same folder as .json file. * From 4bff7ab39fd43dff5c34eee89ff028fc1b387b1a Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Wed, 10 Mar 2021 16:37:17 +0100 Subject: [PATCH 43/54] Remove unused imports --- .../litiengine/graphics/animation/AsepriteHandler.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 6631eb174..cf74e9301 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -7,18 +7,14 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.awt.Dimension; -import java.awt.Image; import java.awt.image.BufferedImage; import java.util.Set; import java.util.Map; import java.util.HashMap; -import java.util.List; -import java.util.Arrays; import javax.imageio.ImageIO; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonObject; From e359ce3d5469af60f998e12838215b123b461ce9 Mon Sep 17 00:00:00 2001 From: Yu Zhou Date: Wed, 10 Mar 2021 19:21:22 +0100 Subject: [PATCH 44/54] Add some unit tests for exportAnimation method. --- .../animation/AsepriteHandlerTests.java | 81 +++++-------------- 1 file changed, 19 insertions(+), 62 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 6aa8acb05..f02d41aed 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -11,79 +11,21 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; -import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.Test; import de.gurkenlabs.litiengine.graphics.Spritesheet; -import de.gurkenlabs.litiengine.graphics.animation.Animation; import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler.ImportAnimationException; +import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler.ExportAnimationException; import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.SpritesheetResource; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.SerializedName; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonObject; -import static org.junit.jupiter.api.Assertions.*; + public class AsepriteHandlerTests { - /** - * Tests that Aseprite animation import works as expected when given valid input. - */ - @Test - public void importAsepriteAnimationTest() { - try { - Animation animation = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json"); - assertEquals("Sprite-0001-sheet", animation.getName()); - assertEquals(300, animation.getTotalDuration()); - for (int keyFrameDuration : animation.getKeyFrameDurations()) - assertEquals(100, keyFrameDuration); - - Spritesheet spriteSheet = animation.getSpritesheet(); - assertEquals(32, spriteSheet.getSpriteHeight()); - assertEquals(32, spriteSheet.getSpriteWidth()); - assertEquals(3, spriteSheet.getTotalNumberOfSprites()); - assertEquals(1, spriteSheet.getRows()); - assertEquals(3, spriteSheet.getColumns()); - assertEquals(ImageFormat.PNG, spriteSheet.getImageFormat()); - - BufferedImage image = spriteSheet.getImage(); - assertEquals(96, image.getWidth()); - assertEquals(32, image.getHeight()); - } catch (FileNotFoundException e) { - fail(e.getMessage()); - } catch (IOException e) { - fail(e.getMessage()); - } catch (AsepriteHandler.ImportAnimationException e) { - fail(e.getMessage()); - } - } - - /** - * Test that if AsepriteHandler.ImportAnimationException will be throwed if different frame dimensions are provided. - */ - @Test - public void ImportAnimationExceptionTest() { - - Throwable exception = assertThrows(ImportAnimationException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002.json")); - assertEquals("AsepriteHandler.ImportAnimationException: animation key frames require same dimensions.", exception.getMessage()); - } - /** - * Tests thrown FileNotFoundException when importing an Aseprite animation. - *

- * 1.first, we test if FileNotFoundException would be throwed if .json file cannot be found. - * 2.then we test if FileNotFoundException would be throwed if spritesheet file cannot be found. - */ - @Test - public void FileNotFoundExceptionTest() { - Throwable exception_withoutJsonFile = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json")); - assertEquals("FileNotFoundException: Could not find .json file tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0003.json", exception_withoutJsonFile.getMessage()); - Throwable exception_withoutSpriteSheet = assertThrows(FileNotFoundException.class, () -> AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0004.json")); - assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, or same folder as .json file.", exception_withoutSpriteSheet.getMessage()); - } /** * Test that just create a json. Select some entries in json file to test. @@ -132,8 +74,23 @@ public void exportAnimationTest() { } catch (FileNotFoundException e) { e.printStackTrace(); } - - + } + /** + * Test if exportAnimationException would be thrown when keyframes and spritesheet file have different dimensions. + */ + @Test + public void ExportAnimationExceptionTest(){ + String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png"; + BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); + Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); + Animation animation = new Animation(spritesheet, false, false, 2, 2); + int[] keyFrames = animation.getKeyFrameDurations(); + SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); + spritesheetResource.setKeyframes(keyFrames); + Throwable exception = assertThrows(ExportAnimationException.class, () -> AsepriteHandler.exportAnimation(spritesheetResource)); + assertEquals("Different dimensions of keyframes and sprites in spritesheet", exception.getMessage()); + } + } From fc0f4c1887e81a5019a5ee227022fa4984d3e06d Mon Sep 17 00:00:00 2001 From: Yu Zhou Date: Wed, 10 Mar 2021 19:42:59 +0100 Subject: [PATCH 45/54] Add some unit tests to importAnimation method. --- .../animation/AsepriteHandlerTests.java | 19 +------- .../aseprite_test_animations/Sprite-0005.json | 41 ++++++++++++++++++ .../aseprite_test_animations/Sprite-0005.png | Bin 0 -> 246 bytes 3 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.json create mode 100644 tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.png diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 0961fb48c..4a046cf2f 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -26,6 +26,8 @@ public class AsepriteHandlerTests { public void importAsepriteAnimationTest() { try { Animation animation = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001.json"); + Animation animation2 = AsepriteHandler.importAnimation("tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.json"); + assertEquals("Sprite-0005", animation2.getName()); assertEquals("Sprite-0001-sheet", animation.getName()); assertEquals(300, animation.getTotalDuration()); for (int keyFrameDuration : animation.getKeyFrameDurations()) @@ -75,21 +77,4 @@ public void FileNotFoundExceptionTest() { assertEquals("FileNotFoundException: Could not find sprite sheet file. Expected location is 'image' in .json metadata, or same folder as .json file.", exception_withoutSpriteSheet.getMessage()); } - /** - * Test that just create a json and prints in to standard output. - */ - @Test - public void exportAnimationTest() { - String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png"; - BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); - Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); - Animation animation = new Animation(spritesheet, false, false, 2, 2, 2); - int[] keyFrames = animation.getKeyFrameDurations(); - SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); - spritesheetResource.setKeyframes(keyFrames); - - AsepriteHandler aseprite = new AsepriteHandler(); - String result = aseprite.exportAnimation(spritesheetResource); - System.out.println(result); - } } diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.json b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.json new file mode 100644 index 000000000..d1aed4ced --- /dev/null +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.json @@ -0,0 +1,41 @@ +{ "frames": { + "Sprite-0001 0.png": { + "frame": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + }, + "Sprite-0001 1.png": { + "frame": { "x": 32, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + }, + "Sprite-0001 2.png": { + "frame": { "x": 64, "y": 0, "w": 32, "h": 32 }, + "rotated": false, + "trimmed": false, + "spriteSourceSize": { "x": 0, "y": 0, "w": 32, "h": 32 }, + "sourceSize": { "w": 32, "h": 32 }, + "duration": 100 + } + }, + "meta": { + "app": "http://www.aseprite.org/", + "version": "1.1.9-dev", + "image": "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0002-sheet.png", + "format": "RGBA8888", + "size": { "w": 96, "h": 32 }, + "scale": "1", + "frameTags": [ + ], + "layers": [ + { "name": "Layer 1", "opacity": 255, "blendMode": "normal" } + ] + } + } + \ No newline at end of file diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.png b/tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0005.png new file mode 100644 index 0000000000000000000000000000000000000000..44a7c127f9c5aed232b18eeecdd6217ac91ba2e4 GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^2|%pC!3HGX9;gigQhPmJ978f1-`+UL+ibwonz%wj z!`Q%&Eosh~18xsnq5@exHf+rN|GvXx!yh5}7gh`mejS=Ao#j9N-Cn&{#zTQ2nI)lz zp+~U6kjcOeXq?2$?fgkxl~T{wKM&7*tL^#O{!-XRal=-fSdX{!q)ctP+!%DTmo$Hn zc#{z8aI(tP+jq5O`ux{>dk-cVPBM;8{&#&|N`9}sN@eWc*lPbW|JEZ{W4~A2;oNg_ t<+3d-4=dkQ1znvnfBtTuRR`)L7y=JxPf9wqTpY+{@O1TaS?83{1ORfuVI2Sf literal 0 HcmV?d00001 From 98affeb29f1bfe2335fa217070a86c277d093214 Mon Sep 17 00:00:00 2001 From: Yu Zhou Date: Wed, 10 Mar 2021 22:29:37 +0100 Subject: [PATCH 46/54] Refactor the exportAnimationTest. --- .../animation/AsepriteHandlerTests.java | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index f02d41aed..fafa9267d 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -2,6 +2,7 @@ import java.io.File; import java.io.FileReader; +import java.nio.file.Files; import java.io.IOException; import java.io.FileNotFoundException; @@ -18,15 +19,14 @@ import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.SpritesheetResource; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonObject; -public class AsepriteHandlerTests { - - - +public class AsepriteHandlerTests { /** * Test that just create a json. Select some entries in json file to test. */ @@ -40,40 +40,35 @@ public void exportAnimationTest() { SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); spritesheetResource.setKeyframes(keyFrames); - AsepriteHandler aseprite = new AsepriteHandler(); - String result = aseprite.exportAnimation(spritesheetResource); - - File asepriteJsonFile = new File(result); - try { - JsonElement rootElement = JsonParser.parseReader(new FileReader(asepriteJsonFile)); - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); - JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); - - int frameWidth = frameDimensions.get("w").getAsInt(); - int frameHeight = frameDimensions.get("h").getAsInt(); - assertEquals(32, frameWidth); - assertEquals(32, frameHeight); - - int duration = firstFrameObject.get("duration").getAsInt(); - assertEquals(100, duration); + //AsepriteHandler aseprite = new AsepriteHandler(); + String result = AsepriteHandler.exportAnimation(spritesheetResource); + JsonElement rootElement = JsonParser.parseString(result); + JsonElement frames = rootElement.getAsJsonObject().get("frames"); + JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); + JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); + + int frameWidth = frameDimensions.get("w").getAsInt(); + int frameHeight = frameDimensions.get("h").getAsInt(); + assertEquals(32, frameWidth); + assertEquals(32, frameHeight); + + int duration = firstFrameObject.get("duration").getAsInt(); + assertEquals(100, duration); - JsonElement meta = rootElement.getAsJsonObject().get("meta"); - JsonObject size = meta.getAsJsonObject().get("size").getAsJsonObject(); - int metaWidth = size.get("w").getAsInt(); - int metaHeight = size.get("h").getAsInt(); - assertEquals(96, metaWidth); - assertEquals(32, metaHeight); + JsonElement meta = rootElement.getAsJsonObject().get("meta"); + JsonObject size = meta.getAsJsonObject().get("size").getAsJsonObject(); + int metaWidth = size.get("w").getAsInt(); + int metaHeight = size.get("h").getAsInt(); + assertEquals(96, metaWidth); + assertEquals(32, metaHeight); - JsonElement layers = meta.getAsJsonObject().get("layers"); - int opacity = layers.getAsJsonArray().get(0).getAsJsonObject().get("opacity").getAsInt(); - assertEquals(255, opacity); + JsonElement layers = meta.getAsJsonObject().get("layers"); + int opacity = layers.getAsJsonArray().get(0).getAsJsonObject().get("opacity").getAsInt(); + assertEquals(255, opacity); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } + } /** From a94824eb8c3de544179ddc751341485e617b0768 Mon Sep 17 00:00:00 2001 From: Yu Zhou Date: Wed, 10 Mar 2021 23:08:37 +0100 Subject: [PATCH 47/54] Delete the faulty test. --- .../animation/AsepriteHandlerTests.java | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index fafa9267d..2d70b7930 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -2,7 +2,6 @@ import java.io.File; import java.io.FileReader; -import java.nio.file.Files; import java.io.IOException; import java.io.FileNotFoundException; @@ -19,58 +18,9 @@ import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.SpritesheetResource; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.JsonObject; public class AsepriteHandlerTests { - /** - * Test that just create a json. Select some entries in json file to test. - */ - @Test - public void exportAnimationTest() { - String spritesheetPath = "tests/de/gurkenlabs/litiengine/graphics/animation/aseprite_test_animations/Sprite-0001-sheet.png"; - BufferedImage image = new BufferedImage(96, 32, BufferedImage.TYPE_4BYTE_ABGR); - Spritesheet spritesheet = new Spritesheet(image, spritesheetPath, 32, 32); - Animation animation = new Animation(spritesheet, false, false, 2, 2, 2); - int[] keyFrames = animation.getKeyFrameDurations(); - SpritesheetResource spritesheetResource = new SpritesheetResource(animation.getSpritesheet()); - spritesheetResource.setKeyframes(keyFrames); - - //AsepriteHandler aseprite = new AsepriteHandler(); - String result = AsepriteHandler.exportAnimation(spritesheetResource); - JsonElement rootElement = JsonParser.parseString(result); - JsonElement frames = rootElement.getAsJsonObject().get("frames"); - JsonObject firstFrameObject = frames.getAsJsonObject().entrySet().iterator().next().getValue().getAsJsonObject(); - JsonObject frameDimensions = firstFrameObject.get("sourceSize").getAsJsonObject(); - - int frameWidth = frameDimensions.get("w").getAsInt(); - int frameHeight = frameDimensions.get("h").getAsInt(); - assertEquals(32, frameWidth); - assertEquals(32, frameHeight); - - int duration = firstFrameObject.get("duration").getAsInt(); - assertEquals(100, duration); - - JsonElement meta = rootElement.getAsJsonObject().get("meta"); - JsonObject size = meta.getAsJsonObject().get("size").getAsJsonObject(); - int metaWidth = size.get("w").getAsInt(); - int metaHeight = size.get("h").getAsInt(); - assertEquals(96, metaWidth); - assertEquals(32, metaHeight); - - JsonElement layers = meta.getAsJsonObject().get("layers"); - int opacity = layers.getAsJsonArray().get(0).getAsJsonObject().get("opacity").getAsInt(); - assertEquals(255, opacity); - - - - - } - /** * Test if exportAnimationException would be thrown when keyframes and spritesheet file have different dimensions. */ From ec12f2f731bd0b815fb7bdc76c8e60e1682ee24c Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Wed, 10 Mar 2021 23:35:44 +0100 Subject: [PATCH 48/54] Fix formatting --- .../litiengine/graphics/animation/AsepriteHandlerTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 2c9cb2af8..8fdeaa796 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -17,6 +17,7 @@ import de.gurkenlabs.litiengine.graphics.animation.AsepriteHandler.ExportAnimationException; import de.gurkenlabs.litiengine.resources.ImageFormat; import de.gurkenlabs.litiengine.resources.SpritesheetResource; + public class AsepriteHandlerTests { /** * Tests that Aseprite animation import works as expected when given valid input. From d1cc4e623e295907fe59acf8932e1ed574fa60c5 Mon Sep 17 00:00:00 2001 From: Daniel Halvarsson Date: Wed, 10 Mar 2021 23:42:39 +0100 Subject: [PATCH 49/54] Fix formatting --- .../litiengine/graphics/animation/AsepriteHandlerTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index 8fdeaa796..bcbc1b3bf 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -19,6 +19,7 @@ import de.gurkenlabs.litiengine.resources.SpritesheetResource; public class AsepriteHandlerTests { + /** * Tests that Aseprite animation import works as expected when given valid input. */ From ce1269bb1a8fd3202e438fd3cd88b5a84d2a79da Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 16 Mar 2021 13:26:14 -0400 Subject: [PATCH 50/54] Remove unused imports --- .../litiengine/graphics/animation/AsepriteHandler.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index cf74e9301..7e8d6b75b 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -20,8 +20,6 @@ import com.google.gson.JsonObject; import de.gurkenlabs.litiengine.graphics.Spritesheet; -import de.gurkenlabs.litiengine.graphics.animation.Animation; -import de.gurkenlabs.litiengine.graphics.animation.KeyFrame; import de.gurkenlabs.litiengine.resources.Resources; import de.gurkenlabs.litiengine.resources.SpritesheetResource; From 03ad6acba7ce41beb8e894c64d942bd24c2bc69b Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 16 Mar 2021 13:32:55 -0400 Subject: [PATCH 51/54] Subclass IOException not Error --- .../graphics/animation/AsepriteHandler.java | 26 ++++++++++++++++--- .../animation/AsepriteHandlerTests.java | 2 -- .../gurkenlabs/utiliti/components/Editor.java | 2 +- .../utiliti/swing/AssetPanelItem.java | 2 +- 4 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 7e8d6b75b..7c7c2c940 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -32,10 +32,18 @@ public class AsepriteHandler { /** * Thrown to indicate error when importing Aseprite JSON format. */ - public static class ImportAnimationException extends Error { + public static class ImportAnimationException extends IOException { public ImportAnimationException(String message) { super(message); } + + public ImportAnimationException(String message, Throwable cause) { + super(message, cause); + } + + public ImportAnimationException(Throwable cause) { + super(cause); + } } /** @@ -206,10 +214,18 @@ public static int[] getKeyFrameDurations(JsonElement rootElement) { /** * Error that is thrown by the export class */ - public static class ExportAnimationException extends Error { + public static class ExportAnimationException extends IOException { public ExportAnimationException(String message) { super(message); } + + public ExportAnimationException(String message, Throwable cause) { + super(message, cause); + } + + public ExportAnimationException(Throwable cause) { + super(cause); + } } /** @@ -217,8 +233,9 @@ public ExportAnimationException(String message) { * This is the public accesible function and can/should be changed to fit into the UI. * * @param spritesheetResource the animation object to export + * @throws ExportAnimationException if the export fails */ - public static String exportAnimation(SpritesheetResource spritesheetResource) { + public static String exportAnimation(SpritesheetResource spritesheetResource) throws ExportAnimationException { String json = createJson(spritesheetResource); return json; } @@ -228,8 +245,9 @@ public static String exportAnimation(SpritesheetResource spritesheetResource) { * * @param spritesheetResource spritesheetResource object to export as json. * @return the json as a string. + * @throws ExportAnimationException if the export fails */ - private static String createJson(SpritesheetResource spritesheetResource) { + private static String createJson(SpritesheetResource spritesheetResource) throws ExportAnimationException { Spritesheet spritesheet = Resources.spritesheets().load(spritesheetResource); assert spritesheet != null; int[] keyframes = Resources.spritesheets().getCustomKeyFrameDurations(spritesheet); diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index bcbc1b3bf..d0f56c83a 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -48,8 +48,6 @@ public void importAsepriteAnimationTest() { fail(e.getMessage()); } catch (IOException e) { fail(e.getMessage()); - } catch (AsepriteHandler.ImportAnimationException e) { - fail(e.getMessage()); } } diff --git a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java index d5c014810..108b3c2c8 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java +++ b/utiliti/src/de/gurkenlabs/utiliti/components/Editor.java @@ -516,7 +516,7 @@ public void processAnimation(File file) { } this.loadSpriteSheets(sprites, true); - } catch (AsepriteHandler.ImportAnimationException | IOException e) { + } catch (IOException e) { log.log(Level.SEVERE, e.getMessage(), e); } } diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java index 8ceb6e59b..8561ed55a 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java @@ -486,7 +486,7 @@ private void exportSpritesheet() { break; } } - } catch (AsepriteHandler.ExportAnimationException | IOException e) { + } catch (IOException e) { log.log(Level.SEVERE, e.getMessage(), e); } } From 920ddd2b4c6ffc4bc8766c64d3e90e351291f435 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 16 Mar 2021 13:54:38 -0400 Subject: [PATCH 52/54] Fix build error Fixes a build error. The error was: ``` /home/gamebuster/Desktop/Modding/LitiEngine/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java:270: error: cannot infer type arguments for HashMap Map frame = new HashMap<>() {{ ^ reason: cannot use '<>' with anonymous inner classes where K,V are type-variables: K extends Object declared in class HashMap V extends Object declared in class HashMap ``` --- .../litiengine/graphics/animation/AsepriteHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java index 7c7c2c940..70318e23e 100644 --- a/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java +++ b/src/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandler.java @@ -267,19 +267,19 @@ private static String createJson(SpritesheetResource spritesheetResource) throws for (int j = 0; j < numCol; j++) { final int row = i; final int col = j; - Map frame = new HashMap<>() {{ + Map frame = new HashMap() {{ put("x", (0 + col * frameWidth)); put("y", (0 + row * frameHeight)); put("w", frameWidth); put("h", frameHeight); }}; - Map spriteSourceSize = new HashMap<>() {{ + Map spriteSourceSize = new HashMap() {{ put("x", 0); put("y", 0); put("w", frameWidth); put("h", frameHeight); }}; - Map sourceSize = new HashMap<>() {{ + Map sourceSize = new HashMap() {{ put("w", frameWidth); put("h", frameHeight); }}; @@ -298,7 +298,7 @@ private static String createJson(SpritesheetResource spritesheetResource) throws // Build the meta object in the json int spritesheetWidth = frameWidth * numCol; int spritesheetHeight = frameHeight * numRows; - Map size = new HashMap<>() {{ + Map size = new HashMap() {{ put("w", spritesheetWidth); put("h", spritesheetHeight); }}; From 7d657a2033f74301a762b87f6652c191ade75143 Mon Sep 17 00:00:00 2001 From: Gamebuster19901 Date: Tue, 16 Mar 2021 13:55:05 -0400 Subject: [PATCH 53/54] Remove unused imports --- .../litiengine/graphics/animation/AsepriteHandlerTests.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java index d0f56c83a..808a42c7d 100644 --- a/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java +++ b/tests/de/gurkenlabs/litiengine/graphics/animation/AsepriteHandlerTests.java @@ -1,10 +1,8 @@ package de.gurkenlabs.litiengine.graphics.animation; -import java.io.File; -import java.io.FileReader; - import java.io.IOException; import java.io.FileNotFoundException; + import java.awt.image.BufferedImage; import static org.junit.jupiter.api.Assertions.fail; From f06ad52858b796e9f392c9a13bf1e1d7431bf9fe Mon Sep 17 00:00:00 2001 From: hannessu Date: Wed, 17 Mar 2021 13:08:30 +0100 Subject: [PATCH 54/54] Update AssetPanelItem.java Removed unnecessary catch block. Any exceptions are caught by the overarching catch-block instead. --- utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java index 8561ed55a..92c1dcc4c 100644 --- a/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java +++ b/utiliti/src/de/gurkenlabs/utiliti/swing/AssetPanelItem.java @@ -479,8 +479,6 @@ private void exportSpritesheet() { try (Writer writer = new FileWriter(fileNameWithExtension)) { writer.write(json); log.log(Level.INFO, "Exported {0} {1} to {2}", new Object[]{"Spritesheet", spriteSheetInfo.getName(), fileNameWithExtension}); - } catch (IOException e) { - e.printStackTrace(); } } break;