Commit vor dem Einfügen von Gebierge über Voxels
This commit is contained in:
@@ -3549,6 +3549,7 @@ public class EditorApp extends Application {
|
||||
Files.deleteIfExists(p);
|
||||
item.getParent().getChildren().remove(item);
|
||||
itemPaths.remove(item);
|
||||
if (pStr.endsWith(".j3o")) deleteJ3oSideFiles(p);
|
||||
setStatus("Gelöscht: " + p.getFileName());
|
||||
} catch (IOException ex) {
|
||||
setStatus("Fehler: " + ex.getMessage());
|
||||
@@ -3837,6 +3838,32 @@ public class EditorApp extends Application {
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Löscht Thumbnail und Impostor-Textur, die zu einer .j3o-Datei gehören.
|
||||
* Impostor-Dateien werden anhand des Zeitstempel-Suffixes (_YYYYMMDD_HHMMSS) ermittelt.
|
||||
*/
|
||||
private void deleteJ3oSideFiles(Path j3oPath) {
|
||||
// Thumbnail
|
||||
try {
|
||||
Files.deleteIfExists(
|
||||
de.blight.editor.state.ThumbnailRenderer.sidecarPath(j3oPath, ASSET_ROOT));
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
// Impostor: Zeitstempel aus Dateiname extrahieren und passende Datei suchen
|
||||
String base = j3oPath.getFileName().toString().replace(".j3o", "");
|
||||
java.util.regex.Matcher m = java.util.regex.Pattern
|
||||
.compile(".*(\\d{8}_\\d{6})$").matcher(base);
|
||||
if (!m.matches()) return;
|
||||
String ts = m.group(1);
|
||||
Path impostorDir = ASSET_ROOT.resolve(
|
||||
de.blight.editor.state.ThumbnailRenderer.IMPOSTOR_DIR);
|
||||
if (!Files.isDirectory(impostorDir)) return;
|
||||
try (var stream = Files.list(impostorDir)) {
|
||||
stream.filter(f -> f.getFileName().toString().endsWith("_" + ts + ".png"))
|
||||
.forEach(f -> { try { Files.deleteIfExists(f); } catch (IOException ignored) {} });
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Befüllt den Asset-Baum vollständig aus dem Dateisystem.
|
||||
* Bekannte Verzeichnisse werden den Kategorie-Feldern zugewiesen;
|
||||
@@ -3851,6 +3878,11 @@ public class EditorApp extends Application {
|
||||
List<Path> topDirs;
|
||||
try (var s = Files.list(ASSET_ROOT)) {
|
||||
topDirs = s.filter(Files::isDirectory)
|
||||
.filter(p -> {
|
||||
String n = p.getFileName().toString();
|
||||
return !n.equals(de.blight.editor.state.ThumbnailRenderer.THUMB_DIR)
|
||||
&& !n.equals(de.blight.editor.state.ThumbnailRenderer.IMPOSTOR_DIR);
|
||||
})
|
||||
.sorted(Comparator.comparing(p -> p.getFileName().toString().toLowerCase()))
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
} catch (IOException e) { topDirs = List.of(); }
|
||||
|
||||
@@ -599,12 +599,12 @@ public class EzTreeState extends BaseAppState {
|
||||
img.setRGB(x, height - 1 - y, (a<<24)|(r<<16)|(g<<8)|b);
|
||||
}
|
||||
}
|
||||
Path texDir = ASSET_ROOT.resolve("Textures").resolve("impostor");
|
||||
Path texDir = ASSET_ROOT.resolve(ThumbnailRenderer.IMPOSTOR_DIR);
|
||||
Files.createDirectories(texDir);
|
||||
File pngFile = texDir.resolve(name + ".png").toFile();
|
||||
ImageIO.write(img, "PNG", pngFile);
|
||||
try {
|
||||
return (Texture2D) assets.loadTexture("Textures/impostor/" + name + ".png");
|
||||
return (Texture2D) assets.loadTexture(ThumbnailRenderer.IMPOSTOR_DIR + "/" + name + ".png");
|
||||
} catch (Exception ignored) {
|
||||
pixels.rewind();
|
||||
Image jmeImg = new Image(Image.Format.RGBA8, width, height, pixels, null,
|
||||
|
||||
@@ -28,6 +28,9 @@ import java.nio.file.Path;
|
||||
*/
|
||||
public class ModelEditorState extends BaseAppState {
|
||||
|
||||
private static final java.nio.file.Path ASSET_ROOT =
|
||||
de.blight.editor.ProjectRoot.resolve("blight-assets", "src", "main", "resources");
|
||||
|
||||
// ── Orbit-Kamera ─────────────────────────────────────────────────────────
|
||||
private static final float ORBIT_SENS = 0.4f; // Grad / Pixel Maus-Delta
|
||||
private static final float ZOOM_FACTOR = 0.1f;
|
||||
@@ -421,7 +424,7 @@ public class ModelEditorState extends BaseAppState {
|
||||
Spatial modelClone = modelWrapper.clone();
|
||||
byte[] thumb = ThumbnailRenderer.render(modelClone, app.getRenderManager(), app.getRenderer());
|
||||
if (thumb == null) return;
|
||||
ThumbnailRenderer.saveSidecar(thumb, j3oPath);
|
||||
ThumbnailRenderer.saveSidecar(thumb, j3oPath, ASSET_ROOT);
|
||||
embedThumbnail(thumb, j3oPath);
|
||||
} catch (Exception e) {
|
||||
System.err.println("[ModelEditor] Thumbnail-Fehler: " + e.getMessage());
|
||||
|
||||
@@ -1250,7 +1250,7 @@ public class SceneObjectState extends BaseAppState {
|
||||
ThumbnailRenderer.embed(model, thumb);
|
||||
Files.createDirectories(req.destJ3o().getParent());
|
||||
BinaryExporter.getInstance().save(model, req.destJ3o().toFile());
|
||||
ThumbnailRenderer.saveSidecar(thumb, req.destJ3o());
|
||||
ThumbnailRenderer.saveSidecar(thumb, req.destJ3o(), ASSET_ROOT);
|
||||
} else {
|
||||
Files.createDirectories(req.destJ3o().getParent());
|
||||
BinaryExporter.getInstance().save(model, req.destJ3o().toFile());
|
||||
|
||||
@@ -128,19 +128,28 @@ public final class ThumbnailRenderer {
|
||||
|
||||
public static String getUserDataKey() { return USERDATA_KEY; }
|
||||
|
||||
/** Speichert PNG-Bytes als {@code <j3oPath>.thumb.png}. */
|
||||
public static void saveSidecar(byte[] pngBytes, Path j3oPath) {
|
||||
/** Name des zentralen Thumbnail-Verzeichnisses (direkt unter assetRoot). */
|
||||
public static final String THUMB_DIR = ".thumbnails";
|
||||
|
||||
/** Name des zentralen Impostor-Textur-Verzeichnisses (direkt unter assetRoot). */
|
||||
public static final String IMPOSTOR_DIR = ".impostors";
|
||||
|
||||
/** Speichert PNG-Bytes ins zentrale Thumbnail-Verzeichnis ({@code assetRoot/.thumbnails/…}). */
|
||||
public static void saveSidecar(byte[] pngBytes, Path j3oPath, Path assetRoot) {
|
||||
if (pngBytes == null) return;
|
||||
try {
|
||||
Files.write(sidecarPath(j3oPath), pngBytes);
|
||||
Path dest = sidecarPath(j3oPath, assetRoot);
|
||||
Files.createDirectories(dest.getParent());
|
||||
Files.write(dest, pngBytes);
|
||||
} catch (IOException e) {
|
||||
System.err.println("[ThumbnailRenderer] Sidecar-Fehler: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** Pfad der Sidecar-Datei: {@code <j3oPath>.thumb.png}. */
|
||||
public static Path sidecarPath(Path j3oPath) {
|
||||
return j3oPath.resolveSibling(j3oPath.getFileName() + ".thumb.png");
|
||||
/** Pfad der Thumbnail-Datei: {@code assetRoot/.thumbnails/<relative-j3o-pfad>.thumb.png}. */
|
||||
public static Path sidecarPath(Path j3oPath, Path assetRoot) {
|
||||
Path rel = assetRoot.relativize(j3oPath);
|
||||
return assetRoot.resolve(THUMB_DIR).resolve(rel.toString() + ".thumb.png");
|
||||
}
|
||||
|
||||
// ── Intern ───────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -593,14 +593,14 @@ public class TreeGeneratorState extends BaseAppState {
|
||||
img.setRGB(x, height - 1 - y, (a<<24)|(r<<16)|(g<<8)|b);
|
||||
}
|
||||
}
|
||||
Path texDir = ASSET_ROOT.resolve("Textures").resolve("impostor");
|
||||
Path texDir = ASSET_ROOT.resolve(ThumbnailRenderer.IMPOSTOR_DIR);
|
||||
Files.createDirectories(texDir);
|
||||
File pngFile = texDir.resolve(name + ".png").toFile();
|
||||
ImageIO.write(img, "PNG", pngFile);
|
||||
log.info("[Blight-Baum] Impostor: {}", pngFile.getAbsolutePath());
|
||||
|
||||
try {
|
||||
return (Texture2D) assets.loadTexture("Textures/impostor/" + name + ".png");
|
||||
return (Texture2D) assets.loadTexture(ThumbnailRenderer.IMPOSTOR_DIR + "/" + name + ".png");
|
||||
} catch (Exception loadEx) {
|
||||
pixels.rewind();
|
||||
Image jmeImg = new Image(Image.Format.RGBA8, width, height,
|
||||
|
||||
@@ -8,7 +8,7 @@ import javafx.scene.image.ImageView;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.stage.Modality;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import de.blight.editor.state.ThumbnailRenderer;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.*;
|
||||
@@ -18,7 +18,7 @@ import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Dialog zum Auswählen eines .j3o-Modells.
|
||||
* Zeigt Karten mit 128×128-Thumbnail wenn eine {@code .j3o.thumb.png} Sidecar-Datei vorhanden ist.
|
||||
* Zeigt Karten mit 128×128-Thumbnail wenn eine Thumbnail-Datei im zentralen {@code .thumbnails}-Verzeichnis vorhanden ist.
|
||||
* Gibt den relativen Asset-Pfad (z.B. "Models/Items/sword.j3o") zurück oder {@code null} bei Abbruch.
|
||||
*/
|
||||
public class ModelChooser extends Dialog<String> {
|
||||
@@ -113,8 +113,7 @@ public class ModelChooser extends Dialog<String> {
|
||||
}
|
||||
|
||||
private Image loadThumb(Path j3o) {
|
||||
// Sidecar: <model.j3o>.thumb.png
|
||||
Path sidecar = j3o.resolveSibling(j3o.getFileName() + ".thumb.png");
|
||||
Path sidecar = ThumbnailRenderer.sidecarPath(j3o, assetRoot);
|
||||
if (Files.isRegularFile(sidecar)) {
|
||||
try (InputStream is = Files.newInputStream(sidecar)) {
|
||||
return new Image(is, THUMB_SIZE, THUMB_SIZE, true, true);
|
||||
|
||||
Reference in New Issue
Block a user