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;