From 0210593213db566d6c3130e9adb18fd533a9ccd7 Mon Sep 17 00:00:00 2001
From: Aloento <11802769+Aloento@users.noreply.github.com>
Date: Sun, 21 Jan 2024 16:48:19 +0100
Subject: [PATCH] The most significant changes involve the refactoring of
thread creation in `Loader.java` and `RecordFX.java`, the addition of a new
dependency in the `pom.xml` file, and the replacement of the `toPixmap()`
method with `flipY()` in `RecordFX.java`.
1. The `pom.xml` file has been updated to include a new dependency for `javafx-swing` version `21.0.2`. This change suggests that the project is transitioning to use JavaFX for its GUI components.
2. In `Loader.java` and `RecordFX.java`, the creation of new threads has been refactored. Instead of directly creating and starting a new thread, a `Thread` object named `load` is created, set as a daemon thread, and then started. This change improves the manageability of threads in the application.
3. The `RecordFX.java` file has seen several changes. Import statements for `com.badlogic.gdx.Gdx`, `com.badlogic.gdx.graphics.Pixmap`, and `com.badlogic.gdx.graphics.PixmapIO` have been removed, while import statements for `javafx.embed.swing.SwingFXUtils`, `javafx.scene.image.PixelWriter`, `javafx.scene.image.WritableImage`, `javafx.scene.paint.Color`, and `javax.imageio.ImageIO` have been added. This indicates a shift from using the libGDX library to the JavaFX library for image processing.
4. The `toPixmap()` method in `RecordFX.java` has been replaced with `flipY()`, which creates a `WritableImage` instead of a `Pixmap`. The `writePNG()` method has also been updated to work with `WritableImage` instead of `Pixmap`, and now uses `ImageIO.write()` instead of `PixmapIO.writePNG()`. These changes further confirm the transition from libGDX to JavaFX for image processing.
5. In `SpineController.java`, the `fitWidthProperty()` and `fitHeightProperty()` listeners and bindings have been updated to add `350` and `50` respectively, instead of `368` and `103`. This change suggests a modification in the dimensions of some GUI components.
6. The `Main.recording` boolean is now set to `true` on the JavaFX Application Thread using `Platform.runLater()`. This ensures that the recording status is updated in a thread-safe manner.
7. In `ExporterController.java`, the `Start()` method of `RecordFX` is now called on a new virtual thread. This change improves the responsiveness of the application by offloading potentially time-consuming operations to a separate thread.
---
README-Eng.md | 6 ++-
README.md | 6 ++-
pom.xml | 7 ++-
src/main/java/to/aloen/ssv/Loader.java | 6 ++-
src/main/java/to/aloen/ssv/RecordFX.java | 52 +++++++++++--------
.../ssv/controller/ExporterController.java | 6 ++-
.../aloen/ssv/controller/SpineController.java | 8 +--
7 files changed, 57 insertions(+), 34 deletions(-)
diff --git a/README-Eng.md b/README-Eng.md
index e9fc240..3d9ed1c 100644
--- a/README-Eng.md
+++ b/README-Eng.md
@@ -4,7 +4,7 @@ A tool to load and export Spine animations
**Java 21** required
Pixel Buffers support required
Exporting MOV requires FFmpeg
-Current version: 2.0.5
+Current version: 2.1.0
![霜叶](https://i0.hdslb.com/bfs/album/98b4fd8a12bc6dbf691b967bed625db67713dff0.png@518w.png "明日方舟 - 霜叶")
@@ -12,6 +12,10 @@ Current version: 2.0.5
[**Released Stable Version**](https://github.com/Aloento/SuperSpineViewer/releases/latest)
+```bash
+java -XX:MaxRAMPercentage=75.0 --enable-preview -jar SuperSpineViewer.jar
+```
+
### Performance Settings Reference
* High Resolution (Camera) = High Memory Requirements
diff --git a/README.md b/README.md
index a18c3de..ded6201 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@
需要 **Java 21 21 21**
需要 像素缓冲区支持
导出 MOV 需要 FFmpeg
-当前版本:2.0.5
+当前版本:2.1.0
![霜叶](https://i0.hdslb.com/bfs/album/98b4fd8a12bc6dbf691b967bed625db67713dff0.png@518w.png "明日方舟 - 霜叶")
@@ -14,6 +14,10 @@
[**发布的稳定版本**](https://github.com/Aloento/SuperSpineViewer/releases/latest)
+```bash
+java -XX:MaxRAMPercentage=75.0 --enable-preview -jar SuperSpineViewer.jar
+```
+
### 性能设置参考
* 高分辨率 (Camera) = 高内存需求
diff --git a/pom.xml b/pom.xml
index 768701d..6b01db4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
to.aloen
SuperSpineViewer
- 2.0.5
+ 2.1.0
sonatype
@@ -88,6 +88,11 @@
javafx-fxml
21.0.2
+
+ org.openjfx
+ javafx-swing
+ 21.0.2
+
org.rationalityfrontline.workaround
jfoenix
diff --git a/src/main/java/to/aloen/ssv/Loader.java b/src/main/java/to/aloen/ssv/Loader.java
index 1909ff7..b002f2c 100644
--- a/src/main/java/to/aloen/ssv/Loader.java
+++ b/src/main/java/to/aloen/ssv/Loader.java
@@ -131,12 +131,14 @@ public static void init() {
gdxApp = new LwjglFXApplication(adapter, Main.spineRender);
}
} else {
- new Thread(() -> {
+ Thread load = new Thread(() -> {
if (Main.spineController.isLoaded()) {
gdxApp = new LwjglFXApplication(adapter, Main.spineRender);
Main.spineController = null;
}
- }, "Loading").start();
+ }, "Loading");
+ load.setDaemon(true);
+ load.start();
}
}
}
diff --git a/src/main/java/to/aloen/ssv/RecordFX.java b/src/main/java/to/aloen/ssv/RecordFX.java
index a5889ca..81afdfa 100644
--- a/src/main/java/to/aloen/ssv/RecordFX.java
+++ b/src/main/java/to/aloen/ssv/RecordFX.java
@@ -1,30 +1,34 @@
package to.aloen.ssv;
-import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.graphics.Pixmap;
-import com.badlogic.gdx.graphics.PixmapIO;
import javafx.application.Platform;
+import javafx.embed.swing.SwingFXUtils;
import javafx.scene.image.PixelReader;
+import javafx.scene.image.PixelWriter;
+import javafx.scene.image.WritableImage;
+import javafx.scene.paint.Color;
import to.aloen.spine.Spine;
+import javax.imageio.ImageIO;
import java.io.File;
+import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
-import java.util.zip.Deflater;
public abstract class RecordFX {
private static final LinkedBlockingQueue savePool = new LinkedBlockingQueue<>() {{
- new Thread(() -> {
+ Thread saving = new Thread(() -> {
while (true) {
try {
take().run();
} catch (InterruptedException ignored) {
}
}
- }).start();
+ }, "Long Saving");
+ saving.setDaemon(true);
+ saving.start();
}};
private static String fileName;
@@ -49,7 +53,7 @@ public static void Start(String fileName) {
Thread.onSpinWait();
RecordFX.fileName = fileName;
- Main.recording = true;
+ Platform.runLater(() -> Main.recording = true);
}
}
@@ -127,28 +131,30 @@ private static void encodeFX() {
});
}
- private static Pixmap toPixmap(final PixelReader image) {
- final Pixmap pixmap = new Pixmap(Main.width, Main.height, Pixmap.Format.RGBA8888);
+ private static WritableImage flipY(final PixelReader image) {
+ final WritableImage flippedImage = new WritableImage(Main.width, Main.height);
+ final PixelWriter pixelWriter = flippedImage.getPixelWriter();
- for (int h = 0; h < Main.height; h++) {
- for (int w = 0; w < Main.width; w++) {
- int argb = image.getArgb(w, h);
- pixmap.drawPixel(w, h, (argb << 8) | (argb >>> 24));
+ for (int y = 0; y < Main.height; y++) {
+ for (int x = 0; x < Main.width; x++) {
+ Color color = image.getColor(x, y);
+ pixelWriter.setColor(x, Main.height - 1 - y, color);
}
}
- return pixmap;
+ return flippedImage;
}
- private static void writePNG(final Pixmap pixmap, final short index) {
+ private static void writePNG(final WritableImage image, final short index) {
try {
- PixmapIO.writePNG(Gdx.files.absolute(
- STR."\{Main.outPath}\{fileName}_Sequence\{File.separator}\{fileName}_\{index}.png"),
- pixmap, Deflater.NO_COMPRESSION, true
- );
- } finally {
- pixmap.dispose();
+ File outputFile = new File(STR."\{Main.outPath}\{fileName}_Sequence\{File.separator}\{fileName}_\{index}.png");
+ outputFile.getParentFile().mkdirs();
+ outputFile.createNewFile();
+ ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", outputFile);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
if (!Main.recording) {
var percent = (double) items++ / counter;
Platform.runLater(() -> Main.progressBar.setProgress(percent));
@@ -170,9 +176,9 @@ private Task(PixelReader image, short counter) {
@Override
public void run() {
- final Pixmap pixmap = toPixmap(image);
+ final WritableImage flipY = flipY(image);
image = null;
- writePNG(pixmap, counter);
+ writePNG(flipY, counter);
}
}
}
diff --git a/src/main/java/to/aloen/ssv/controller/ExporterController.java b/src/main/java/to/aloen/ssv/controller/ExporterController.java
index d3f94bd..a463bd7 100644
--- a/src/main/java/to/aloen/ssv/controller/ExporterController.java
+++ b/src/main/java/to/aloen/ssv/controller/ExporterController.java
@@ -58,8 +58,10 @@ void B_Export() {
Spine.speed.set(Main.quality);
Spine.isPlay.set(true);
- System.out.println("请求:开始录制");
- RecordFX.Start(STR."\{Spine.projectName.get()}_\{Spine.animate.get()}");
+ Thread.startVirtualThread(() -> {
+ RecordFX.Start(STR."\{Spine.projectName.get()}_\{Spine.animate.get()}");
+ System.out.println("请求:开始录制");
+ });
}
}
diff --git a/src/main/java/to/aloen/ssv/controller/SpineController.java b/src/main/java/to/aloen/ssv/controller/SpineController.java
index d6087c4..99d67f9 100644
--- a/src/main/java/to/aloen/ssv/controller/SpineController.java
+++ b/src/main/java/to/aloen/ssv/controller/SpineController.java
@@ -317,13 +317,13 @@ public void initialize(URL location, ResourceBundle resources) {
fitWidthProperty().addListener((_, _, newValue) -> {
T_Width.setPromptText(String.valueOf(newValue.intValue()));
width = newValue.intValue();
- Pref.putDouble("stageWidth", newValue.doubleValue() + 368);
+ Pref.putDouble("stageWidth", newValue.doubleValue() + 350);
});
fitHeightProperty().addListener((_, _, newValue) -> {
T_Height.setPromptText(String.valueOf(newValue.intValue()));
height = newValue.intValue();
- Pref.putDouble("stageHeight", newValue.doubleValue() + 103);
+ Pref.putDouble("stageHeight", newValue.doubleValue() + 50);
});
}};
@@ -367,8 +367,8 @@ public boolean isLoaded() {
Viewer.getChildren().remove(loadPane);
Viewer.setCenter(spineRender);
- spineRender.fitHeightProperty().bind(spineRender.getScene().heightProperty().add(-103));
- spineRender.fitWidthProperty().bind(spineRender.getScene().widthProperty().add(-368));
+ spineRender.fitHeightProperty().bind(spineRender.getScene().heightProperty().add(-50));
+ spineRender.fitWidthProperty().bind(spineRender.getScene().widthProperty().add(-350));
Viewer = null;
loadPane = null;