Zwischenstand
This commit is contained in:
@@ -498,6 +498,12 @@ public class EditorApp extends Application {
|
||||
if (charEditorStatusLabel != null) charEditorStatusLabel.setText(embedStatus);
|
||||
}
|
||||
|
||||
String stripStatus = input.animStripStatus;
|
||||
if (stripStatus != null) {
|
||||
input.animStripStatus = null;
|
||||
if (charEditorStatusLabel != null) charEditorStatusLabel.setText(stripStatus);
|
||||
}
|
||||
|
||||
String rts = input.randomTreeStatus;
|
||||
if (randomTreeStatusLabel != null && rts != null) {
|
||||
randomTreeStatusLabel.setText(rts);
|
||||
@@ -9452,6 +9458,19 @@ public class EditorApp extends Application {
|
||||
input.animEmbedRequest.set(new SharedInput.AnimEmbedRequest(modelPath, setName));
|
||||
});
|
||||
|
||||
Button stripClipsBtn = new Button("Eingebettete Clips löschen");
|
||||
stripClipsBtn.setMaxWidth(Double.MAX_VALUE);
|
||||
stripClipsBtn.setDisable(true);
|
||||
charModelCombo.valueProperty().addListener((obs, ov, nv) ->
|
||||
stripClipsBtn.setDisable(nv == null || nv.isBlank()));
|
||||
stripClipsBtn.setOnAction(e -> {
|
||||
String modelPath = charModelCombo.getValue();
|
||||
if (modelPath == null || modelPath.isBlank()) return;
|
||||
if (charEditorStatusLabel != null)
|
||||
charEditorStatusLabel.setText("Entferne eingebettete Clips…");
|
||||
input.animStripClipsRequest.set(modelPath);
|
||||
});
|
||||
|
||||
charEditContainer.getChildren().addAll(
|
||||
new Label("ID:"), charIdField,
|
||||
new Label("Name:"), charNameField,
|
||||
@@ -9562,7 +9581,8 @@ public class EditorApp extends Application {
|
||||
charEditContainer.getChildren().addAll(
|
||||
new Label("Modell:"), charModelCombo,
|
||||
new Label("Anim-Set:"), charAnimSetCombo,
|
||||
embedAnimBtn
|
||||
embedAnimBtn,
|
||||
stripClipsBtn
|
||||
);
|
||||
|
||||
// ── Aktions-Zuweisung ──────────────────────────────────────────────────
|
||||
|
||||
@@ -594,10 +594,16 @@ public class SharedInput {
|
||||
public final java.util.concurrent.atomic.AtomicReference<AnimEmbedRequest>
|
||||
animEmbedRequest = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
|
||||
/** JavaFX → JME3: Modell-Pfad, aus dem alle eingebetteten AnimClips entfernt werden sollen. */
|
||||
public final java.util.concurrent.atomic.AtomicReference<String>
|
||||
animStripClipsRequest = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
|
||||
/** JME3 → JavaFX: Status-Meldung für Clip- und Set-Operationen. */
|
||||
public volatile String animOpStatus = null;
|
||||
public volatile String animOpStatus = null;
|
||||
/** JME3 → JavaFX: Status-Meldung für Einbett-Operationen (Character Editor). */
|
||||
public volatile String animEmbedStatus = null;
|
||||
public volatile String animEmbedStatus = null;
|
||||
/** JME3 → JavaFX: Status-Meldung für Strip-Operationen (Clips aus Modell entfernen). */
|
||||
public volatile String animStripStatus = null;
|
||||
|
||||
// ── Modell-Konvertierung ──────────────────────────────────────────────────
|
||||
/**
|
||||
|
||||
@@ -178,6 +178,9 @@ public class AnimPreviewState extends BaseAppState {
|
||||
SharedInput.AnimEmbedRequest embedReq = input.animEmbedRequest.getAndSet(null);
|
||||
if (embedReq != null) executeAnimEmbed(embedReq);
|
||||
|
||||
String stripPath = input.animStripClipsRequest.getAndSet(null);
|
||||
if (stripPath != null) executeStripClips(stripPath);
|
||||
|
||||
// Geschwindigkeit live anpassen
|
||||
if (currentAction != null) {
|
||||
try { currentAction.setSpeed(input.animPreviewSpeed); } catch (Exception ignored) {}
|
||||
@@ -258,6 +261,19 @@ public class AnimPreviewState extends BaseAppState {
|
||||
currentModelPath = assetPath;
|
||||
previewHolder.attachChild(model);
|
||||
|
||||
// Alle Clips in-place snappen (verhindert Drift im Preview)
|
||||
AnimComposer previewAC = findControl(model, AnimComposer.class);
|
||||
SkinningControl previewSC = findControl(model, SkinningControl.class);
|
||||
if (previewAC != null && previewSC != null) {
|
||||
for (AnimClip c : new java.util.ArrayList<>(previewAC.getAnimClips())) {
|
||||
AnimClip snapped = de.blight.game.animation.AnimationLibrary.snapRootBoneXZ(c, previewSC.getArmature());
|
||||
if (snapped != c) {
|
||||
previewAC.removeAnimClip(c);
|
||||
previewAC.addAnimClip(snapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Kamera auf Bounding Box ausrichten
|
||||
model.updateGeometricState();
|
||||
if (model.getWorldBound() instanceof BoundingBox bb) {
|
||||
@@ -498,9 +514,12 @@ public class AnimPreviewState extends BaseAppState {
|
||||
LOG.info("[AnimPreview] Clip '{}' als '{}' gespeichert (Dateiname-Alias)", name, saveName);
|
||||
}
|
||||
|
||||
// XZ-Drift einfrieren bevor gespeichert wird – Clip-Dateien bleiben immer sauber
|
||||
com.jme3.anim.Armature snapArm = dstArm != null ? dstArm : srcArm;
|
||||
toSave = de.blight.game.animation.AnimationLibrary.snapRootBoneXZ(toSave, snapArm);
|
||||
|
||||
// Direkt in die Clip-Bibliothek speichern – das Modell wird nicht modifiziert
|
||||
saveClipToFile(toSave, dstArm != null ? dstArm : srcArm,
|
||||
clipsDir.resolve(saveName + ".j3o"));
|
||||
saveClipToFile(toSave, snapArm, clipsDir.resolve(saveName + ".j3o"));
|
||||
// Für den aktuellen Preview-Session auch auf das Modell anwenden (wenn geladen)
|
||||
if (targetAC != null) targetAC.addAnimClip(toSave);
|
||||
saved++;
|
||||
@@ -925,6 +944,29 @@ public class AnimPreviewState extends BaseAppState {
|
||||
}
|
||||
}
|
||||
|
||||
private void executeStripClips(String modelPath) {
|
||||
try {
|
||||
Spatial model = loadFresh(modelPath);
|
||||
AnimComposer ac = findControl(model, AnimComposer.class);
|
||||
if (ac == null) {
|
||||
input.animStripStatus = "Fehler: kein AnimComposer in " + modelPath;
|
||||
return;
|
||||
}
|
||||
int count = ac.getAnimClips().size();
|
||||
for (AnimClip c : new java.util.ArrayList<>(ac.getAnimClips())) {
|
||||
ac.removeAnimClip(c);
|
||||
}
|
||||
java.nio.file.Path file = ASSET_ROOT.resolve(modelPath.replace('/', java.io.File.separatorChar));
|
||||
BinaryExporter.getInstance().save(model, file.toFile());
|
||||
assets.deleteFromCache(new com.jme3.asset.ModelKey(modelPath));
|
||||
input.animStripStatus = count + " eingebettete Clip(s) aus '" + modelPath + "' entfernt";
|
||||
LOG.info("[AnimStrip] {} Clips aus '{}' entfernt und gespeichert", count, modelPath);
|
||||
} catch (Exception e) {
|
||||
input.animStripStatus = "Strip-Fehler: " + e.getMessage();
|
||||
LOG.error("[AnimStrip] Fehler beim Strip von {}", modelPath, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveClipToFile(AnimClip clip, com.jme3.anim.Armature armature,
|
||||
java.nio.file.Path outFile) throws Exception {
|
||||
Node holder = new Node("clip_" + clip.getName());
|
||||
|
||||
Reference in New Issue
Block a user