Impostor-Texturen: kein Dateisystem-Write mehr, eingebettet in .j3o

saveImpostor() in TreeGeneratorState, PalmGeneratorState und EzTreeState
schreibt keine PNG-Dateien mehr ins .impostors-Verzeichnis. Die Texture2D
wird direkt aus dem In-Memory-ByteBuffer erstellt und via BinaryExporter
in der .j3o-Datei eingebettet. Bestehende .impostors-Dateien entfernt.
deleteJ3oSideFiles() und populateAssetTree() ohne Impostor-Logik.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-07-05 22:27:34 +02:00
parent 4fd337aea4
commit dea1aa3d3e
6 changed files with 15 additions and 117 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 247 KiB

View File

@@ -4887,30 +4887,12 @@ public class EditorApp extends Application {
}
}
/**
* Löscht Thumbnail und Impostor-Textur, die zu einer .j3o-Datei gehören.
* Impostor-Dateien werden anhand des Zeitstempel-Suffixes (_YYYYMMDD_HHMMSS) ermittelt.
*/
/** Löscht Thumbnail, das zu einer .j3o-Datei gehört. */
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) {}
}
/**
@@ -4930,8 +4912,7 @@ public class EditorApp extends Application {
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);
return !n.equals(de.blight.editor.state.ThumbnailRenderer.THUMB_DIR);
})
.sorted(Comparator.comparing(p -> p.getFileName().toString().toLowerCase()))
.collect(java.util.stream.Collectors.toList());

View File

@@ -36,8 +36,6 @@ import de.blight.eztree.TreeOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
@@ -596,32 +594,10 @@ public class EzTreeState extends BaseAppState {
}
private Texture2D saveImpostor(ByteBuffer pixels, String name, int width, int height) {
try {
pixels.rewind();
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int r = pixels.get() & 0xFF, g = pixels.get() & 0xFF,
b = pixels.get() & 0xFF, a = pixels.get() & 0xFF;
img.setRGB(x, height - 1 - y, (a<<24)|(r<<16)|(g<<8)|b);
}
}
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(ThumbnailRenderer.IMPOSTOR_DIR + "/" + name + ".png");
} catch (Exception ignored) {
pixels.rewind();
Image jmeImg = new Image(Image.Format.RGBA8, width, height, pixels, null,
com.jme3.texture.image.ColorSpace.sRGB);
return new Texture2D(jmeImg);
}
} catch (IOException e) {
log.error("[EzTree] Impostor-Fehler: {}", e.getMessage());
return null;
}
pixels.rewind();
Image jmeImg = new Image(Image.Format.RGBA8, width, height, pixels, null,
com.jme3.texture.image.ColorSpace.sRGB);
return new Texture2D(jmeImg);
}
private ByteBuffer combineAtlas(ByteBuffer[] passes) {

View File

@@ -1,6 +1,5 @@
package de.blight.editor.state;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
@@ -9,8 +8,6 @@ import java.nio.file.Path;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.imageio.ImageIO;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
@@ -353,36 +350,10 @@ public class PalmGeneratorState extends BaseAppState {
}
private Texture2D saveImpostor(ByteBuffer pixels, String name, int width, int height) {
try {
pixels.rewind();
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int r = pixels.get() & 0xFF;
int g = pixels.get() & 0xFF;
int b = pixels.get() & 0xFF;
int a = pixels.get() & 0xFF;
img.setRGB(x, height - 1 - y, (a<<24)|(r<<16)|(g<<8)|b);
}
}
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("[Palme] Impostor: {}", pngFile.getAbsolutePath());
try {
return (Texture2D) assets.loadTexture(ThumbnailRenderer.IMPOSTOR_DIR + "/" + name + ".png");
} catch (Exception loadEx) {
pixels.rewind();
Image jmeImg = new Image(Image.Format.RGBA8, width, height,
pixels, null, com.jme3.texture.image.ColorSpace.sRGB);
return new Texture2D(jmeImg);
}
} catch (IOException e) {
log.error("[Palme] Impostor-Fehler: {}", e.getMessage());
return null;
}
pixels.rewind();
Image jmeImg = new Image(Image.Format.RGBA8, width, height,
pixels, null, com.jme3.texture.image.ColorSpace.sRGB);
return new Texture2D(jmeImg);
}
// ── Export ────────────────────────────────────────────────────────────────

View File

@@ -1,17 +1,13 @@
package de.blight.editor.state;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import javax.imageio.ImageIO;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
@@ -580,39 +576,13 @@ public class TreeGeneratorState extends BaseAppState {
return copy;
}
// ── Impostor-PNG speichern ────────────────────────────────────────────────
// ── Impostor-Textur in-memory erzeugen ────────────────────────────────────
private Texture2D saveImpostor(ByteBuffer pixels, String name, int width, int height) {
try {
pixels.rewind();
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int r = pixels.get() & 0xFF;
int g = pixels.get() & 0xFF;
int b = pixels.get() & 0xFF;
int a = pixels.get() & 0xFF;
img.setRGB(x, height - 1 - y, (a<<24)|(r<<16)|(g<<8)|b);
}
}
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(ThumbnailRenderer.IMPOSTOR_DIR + "/" + name + ".png");
} catch (Exception loadEx) {
pixels.rewind();
Image jmeImg = new Image(Image.Format.RGBA8, width, height,
pixels, null, com.jme3.texture.image.ColorSpace.sRGB);
return new Texture2D(jmeImg);
}
} catch (IOException e) {
log.error("[Blight-Baum] Impostor-Fehler: {}", e.getMessage());
return null;
}
pixels.rewind();
Image jmeImg = new Image(Image.Format.RGBA8, width, height,
pixels, null, com.jme3.texture.image.ColorSpace.sRGB);
return new Texture2D(jmeImg);
}
// ── .j3o-Export ───────────────────────────────────────────────────────────