Menü Buttons angepasst, Screenshot Funktion optimiert
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 3.1 KiB |
Binary file not shown.
@@ -1477,6 +1477,7 @@ public class EditorApp extends Application {
|
|||||||
saveItem.setAccelerator(javafx.scene.input.KeyCombination.keyCombination("Ctrl+S"));
|
saveItem.setAccelerator(javafx.scene.input.KeyCombination.keyCombination("Ctrl+S"));
|
||||||
saveItem.setOnAction(e -> { input.saveRequested = true; setStatus("Speichern…"); });
|
saveItem.setOnAction(e -> { input.saveRequested = true; setStatus("Speichern…"); });
|
||||||
MenuItem screenshotItem = new MenuItem("Screenshot");
|
MenuItem screenshotItem = new MenuItem("Screenshot");
|
||||||
|
screenshotItem.setAccelerator(javafx.scene.input.KeyCombination.keyCombination("Ctrl+F12"));
|
||||||
screenshotItem.setOnAction(e -> takeEditorScreenshot());
|
screenshotItem.setOnAction(e -> takeEditorScreenshot());
|
||||||
MenuItem settingsItem = new MenuItem("Einstellungen…");
|
MenuItem settingsItem = new MenuItem("Einstellungen…");
|
||||||
settingsItem.setOnAction(e -> openSettings());
|
settingsItem.setOnAction(e -> openSettings());
|
||||||
@@ -6442,6 +6443,7 @@ public class EditorApp extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void takeEditorScreenshot() {
|
private void takeEditorScreenshot() {
|
||||||
|
playScreenshotClick();
|
||||||
WritableImage image = primaryStage.getScene().snapshot(null);
|
WritableImage image = primaryStage.getScene().snapshot(null);
|
||||||
String timestamp = java.time.LocalDateTime.now()
|
String timestamp = java.time.LocalDateTime.now()
|
||||||
.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
|
.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
|
||||||
@@ -6456,6 +6458,34 @@ public class EditorApp extends Application {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void playScreenshotClick() {
|
||||||
|
Thread t = new Thread(() -> {
|
||||||
|
try {
|
||||||
|
int sr = 44100;
|
||||||
|
int frames = (int) (sr * 0.08);
|
||||||
|
byte[] buf = new byte[frames * 2];
|
||||||
|
java.util.Random rng = new java.util.Random();
|
||||||
|
for (int i = 0; i < frames; i++) {
|
||||||
|
double env = Math.exp(-i / (sr * 0.012));
|
||||||
|
double s = (rng.nextGaussian() * 0.55 + Math.sin(2 * Math.PI * 3200.0 * i / sr) * 0.45) * env * 0.85;
|
||||||
|
short val = (short) Math.max(-32767, Math.min(32767, s * 32767));
|
||||||
|
buf[i * 2] = (byte) (val & 0xff);
|
||||||
|
buf[i * 2 + 1] = (byte) ((val >> 8) & 0xff);
|
||||||
|
}
|
||||||
|
javax.sound.sampled.AudioFormat fmt = new javax.sound.sampled.AudioFormat(sr, 16, 1, true, false);
|
||||||
|
javax.sound.sampled.DataLine.Info info = new javax.sound.sampled.DataLine.Info(javax.sound.sampled.SourceDataLine.class, fmt);
|
||||||
|
javax.sound.sampled.SourceDataLine line = (javax.sound.sampled.SourceDataLine) javax.sound.sampled.AudioSystem.getLine(info);
|
||||||
|
line.open(fmt);
|
||||||
|
line.start();
|
||||||
|
line.write(buf, 0, buf.length);
|
||||||
|
line.drain();
|
||||||
|
line.close();
|
||||||
|
} catch (Exception ignored) {}
|
||||||
|
}, "screenshot-click");
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
private void handleTextureImport(javafx.stage.Window owner) {
|
private void handleTextureImport(javafx.stage.Window owner) {
|
||||||
FileChooser fc = new FileChooser();
|
FileChooser fc = new FileChooser();
|
||||||
fc.setTitle("Texturen importieren (nicht-PNG wird automatisch konvertiert)");
|
fc.setTitle("Texturen importieren (nicht-PNG wird automatisch konvertiert)");
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ public class BlightGame extends SimpleApplication {
|
|||||||
private AudioSettings audioSettings;
|
private AudioSettings audioSettings;
|
||||||
private ScreenshotAppState screenshotState;
|
private ScreenshotAppState screenshotState;
|
||||||
private Path screenshotDir;
|
private Path screenshotDir;
|
||||||
|
private com.jme3.audio.AudioNode screenshotClickSound;
|
||||||
private WorldScene worldScene;
|
private WorldScene worldScene;
|
||||||
private ConfigScreen configScreen;
|
private ConfigScreen configScreen;
|
||||||
private GraphicsScreen graphicsScreen;
|
private GraphicsScreen graphicsScreen;
|
||||||
@@ -380,8 +381,12 @@ public class BlightGame extends SimpleApplication {
|
|||||||
try {
|
try {
|
||||||
screenshotDir = BlightHome.resolve("screenshots");
|
screenshotDir = BlightHome.resolve("screenshots");
|
||||||
Files.createDirectories(screenshotDir);
|
Files.createDirectories(screenshotDir);
|
||||||
screenshotState = new ScreenshotAppState(screenshotDir + File.separator, "screenshot");
|
screenshotState = new ScreenshotAppState("", "screenshot");
|
||||||
stateManager.attach(screenshotState);
|
stateManager.attach(screenshotState);
|
||||||
|
screenshotClickSound = new com.jme3.audio.AudioNode(assetManager, "audio/static/screenshot_click.ogg", com.jme3.audio.AudioData.DataType.Buffer);
|
||||||
|
screenshotClickSound.setPositional(false);
|
||||||
|
screenshotClickSound.setLooping(false);
|
||||||
|
screenshotClickSound.setVolume(1f);
|
||||||
log.info("Screenshots werden gespeichert in: {}", screenshotDir.toAbsolutePath());
|
log.info("Screenshots werden gespeichert in: {}", screenshotDir.toAbsolutePath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.warn("Screenshot-Verzeichnis konnte nicht angelegt werden", e);
|
log.warn("Screenshot-Verzeichnis konnte nicht angelegt werden", e);
|
||||||
@@ -389,8 +394,12 @@ public class BlightGame extends SimpleApplication {
|
|||||||
inputManager.addMapping("Screenshot", new KeyTrigger(KeyInput.KEY_F12));
|
inputManager.addMapping("Screenshot", new KeyTrigger(KeyInput.KEY_F12));
|
||||||
inputManager.addListener((ActionListener) (name, isPressed, tpf) -> {
|
inputManager.addListener((ActionListener) (name, isPressed, tpf) -> {
|
||||||
if (isPressed && screenshotState != null) {
|
if (isPressed && screenshotState != null) {
|
||||||
log.info("[Screenshot] Speichere in: {}", screenshotDir.toAbsolutePath());
|
String ts = java.time.LocalDateTime.now()
|
||||||
|
.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss"));
|
||||||
|
screenshotState.setFileName(screenshotDir + java.io.File.separator + "blight_" + ts + "_");
|
||||||
|
log.info("[Screenshot] Speichere: blight_{}.png", ts);
|
||||||
screenshotState.takeScreenshot();
|
screenshotState.takeScreenshot();
|
||||||
|
if (screenshotClickSound != null) screenshotClickSound.playInstance();
|
||||||
}
|
}
|
||||||
}, "Screenshot");
|
}, "Screenshot");
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import com.jme3.texture.image.ColorSpace;
|
|||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.awt.image.ConvolveOp;
|
||||||
|
import java.awt.image.Kernel;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@@ -127,6 +129,8 @@ public class NinePatch {
|
|||||||
// Guide-Pixel durch Rahmen-Nachbarfarbe ersetzen
|
// Guide-Pixel durch Rahmen-Nachbarfarbe ersetzen
|
||||||
stripGuides(img, w, h, l - 1, w - r, t - 1, h - b);
|
stripGuides(img, w, h, l - 1, w - r, t - 1, h - b);
|
||||||
|
|
||||||
|
img = gaussianBlur(img, 0.0f);
|
||||||
|
|
||||||
Texture2D tex = toJmeTexture(img, w, h);
|
Texture2D tex = toJmeTexture(img, w, h);
|
||||||
return new NinePatch(assets, tex, w, h, l, r, t, b);
|
return new NinePatch(assets, tex, w, h, l, r, t, b);
|
||||||
}
|
}
|
||||||
@@ -219,6 +223,26 @@ public class NinePatch {
|
|||||||
return 0; // Fallback: transparent
|
return 0; // Fallback: transparent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Weicher Gauss-Blur (3×3-Kernel) auf das Bild – glättet Übergänge an Patch-Grenzen.
|
||||||
|
* sigma=0 deaktiviert den Blur.
|
||||||
|
*/
|
||||||
|
private static BufferedImage gaussianBlur(BufferedImage img, float sigma) {
|
||||||
|
if (sigma <= 0f) { return img; }
|
||||||
|
float s2 = 2f * sigma * sigma;
|
||||||
|
float[] data = {
|
||||||
|
(float) Math.exp(-2 / s2), (float) Math.exp(-1 / s2), (float) Math.exp(-2 / s2),
|
||||||
|
(float) Math.exp(-1 / s2), 1f, (float) Math.exp(-1 / s2),
|
||||||
|
(float) Math.exp(-2 / s2), (float) Math.exp(-1 / s2), (float) Math.exp(-2 / s2)
|
||||||
|
};
|
||||||
|
float sum = 0; for (float v : data) sum += v;
|
||||||
|
for (int i = 0; i < data.length; i++) data[i] /= sum;
|
||||||
|
ConvolveOp op = new ConvolveOp(new Kernel(3, 3, data), ConvolveOp.EDGE_NO_OP, null);
|
||||||
|
BufferedImage out = new BufferedImage(img.getWidth(), img.getHeight(), img.getType());
|
||||||
|
op.filter(img, out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Konvertiert ein BufferedImage in eine JME3-Textur.
|
* Konvertiert ein BufferedImage in eine JME3-Textur.
|
||||||
* Zeilen werden von unten nach oben gelesen (entspricht JME3-Y-Flip beim PNG-Laden).
|
* Zeilen werden von unten nach oben gelesen (entspricht JME3-Y-Flip beim PNG-Laden).
|
||||||
@@ -266,7 +290,7 @@ public class NinePatch {
|
|||||||
*/
|
*/
|
||||||
public Node build(float x, float y, float w, float h, float z) {
|
public Node build(float x, float y, float w, float h, float z) {
|
||||||
tex.setWrap(Texture.WrapMode.EdgeClamp);
|
tex.setWrap(Texture.WrapMode.EdgeClamp);
|
||||||
tex.setMagFilter(Texture.MagFilter.Nearest);
|
tex.setMagFilter(Texture.MagFilter.Bilinear);
|
||||||
|
|
||||||
Material mat = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
|
Material mat = new Material(assets, "Common/MatDefs/Misc/Unshaded.j3md");
|
||||||
mat.setTexture("ColorMap", tex);
|
mat.setTexture("ColorMap", tex);
|
||||||
@@ -282,22 +306,75 @@ public class NinePatch {
|
|||||||
float sx1 = x + l, sx2 = x + w - r;
|
float sx1 = x + l, sx2 = x + w - r;
|
||||||
float sy1 = y + b, sy2 = y + h - t;
|
float sy1 = y + b, sy2 = y + h - t;
|
||||||
|
|
||||||
|
// Kachelgröße des Mittelbereichs in Bildschirmpixeln
|
||||||
|
float cw = (u2 - u1) * texW;
|
||||||
|
float ch = (v2 - v1) * texH;
|
||||||
|
|
||||||
Node n = new Node("ninepatch");
|
Node n = new Node("ninepatch");
|
||||||
// Reihe unten
|
// Reihe unten – Ecken fix, untere Kante Mirror-X
|
||||||
n.attachChild(q(mat, x, y, l, b, 0, 0, u1, v1, z));
|
n.attachChild(q(mat, x, y, l, b, 0, 0, u1, v1, z));
|
||||||
n.attachChild(q(mat, sx1, y, sx2-sx1, b, u1, 0, u2, v1, z));
|
tileHEdge(n, mat, sx1, y, sx2, b, u1, u2, 0, v1, cw, texW, z);
|
||||||
n.attachChild(q(mat, sx2, y, r, b, u2, 0, 1, v1, z));
|
n.attachChild(q(mat, sx2, y, r, b, u2, 0, 1, v1, z));
|
||||||
// Reihe mitte
|
// Reihe mitte – Seiten Mirror-Y, Mitte Mirror-X+Y
|
||||||
n.attachChild(q(mat, x, sy1, l, sy2-sy1, 0, v1, u1, v2, z));
|
tileVEdge(n, mat, x, sy1, l, sy2, 0, u1, v1, v2, ch, texH, z);
|
||||||
n.attachChild(q(mat, sx1, sy1, sx2-sx1, sy2-sy1, u1, v1, u2, v2, z));
|
tileCenterQuads(n, mat, sx1, sy1, sx2, sy2, u1, v1, u2, v2, cw, ch, texW, texH, z);
|
||||||
n.attachChild(q(mat, sx2, sy1, r, sy2-sy1, u2, v1, 1, v2, z));
|
tileVEdge(n, mat, sx2, sy1, r, sy2, u2, 1f, v1, v2, ch, texH, z);
|
||||||
// Reihe oben
|
// Reihe oben – Ecken fix, obere Kante Mirror-X
|
||||||
n.attachChild(q(mat, x, sy2, l, t, 0, v2, u1, 1, z));
|
n.attachChild(q(mat, x, sy2, l, t, 0, v2, u1, 1f, z));
|
||||||
n.attachChild(q(mat, sx1, sy2, sx2-sx1, t, u1, v2, u2, 1, z));
|
tileHEdge(n, mat, sx1, sy2, sx2, t, u1, u2, v2, 1f, cw, texW, z);
|
||||||
n.attachChild(q(mat, sx2, sy2, r, t, u2, v2, 1, 1, z));
|
n.attachChild(q(mat, sx2, sy2, r, t, u2, v2, 1f, 1f, z));
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Mitte: Mirror-Repeat in X und Y. */
|
||||||
|
private static void tileCenterQuads(Node n, Material mat,
|
||||||
|
float sx1, float sy1, float sx2, float sy2,
|
||||||
|
float u1, float v1, float u2, float v2,
|
||||||
|
float cw, float ch,
|
||||||
|
float texW, float texH, float z) {
|
||||||
|
int iz = 0;
|
||||||
|
for (float py = sy1; py < sy2; py += ch, iz++) {
|
||||||
|
float th = Math.min(ch, sy2 - py);
|
||||||
|
float vA = (iz & 1) == 0 ? v1 : v2;
|
||||||
|
float vB = (iz & 1) == 0 ? v1+th/texH : v2-th/texH;
|
||||||
|
int ix = 0;
|
||||||
|
for (float px = sx1; px < sx2; px += cw, ix++) {
|
||||||
|
float tw = Math.min(cw, sx2 - px);
|
||||||
|
float uA = (ix & 1) == 0 ? u1 : u2;
|
||||||
|
float uB = (ix & 1) == 0 ? u1+tw/texW : u2-tw/texW;
|
||||||
|
n.attachChild(q(mat, px, py, tw, th, uA, vA, uB, vB, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Horizontaler Randstreifen (oben/unten): Mirror-Repeat nur in X. */
|
||||||
|
private static void tileHEdge(Node n, Material mat,
|
||||||
|
float sx1, float py, float sx2, float ph,
|
||||||
|
float u1, float u2, float vMin, float vMax,
|
||||||
|
float cw, float texW, float z) {
|
||||||
|
int ix = 0;
|
||||||
|
for (float px = sx1; px < sx2; px += cw, ix++) {
|
||||||
|
float tw = Math.min(cw, sx2 - px);
|
||||||
|
float uA = (ix & 1) == 0 ? u1 : u2;
|
||||||
|
float uB = (ix & 1) == 0 ? u1+tw/texW : u2-tw/texW;
|
||||||
|
n.attachChild(q(mat, px, py, tw, ph, uA, vMin, uB, vMax, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Vertikaler Randstreifen (links/rechts): Mirror-Repeat nur in Y. */
|
||||||
|
private static void tileVEdge(Node n, Material mat,
|
||||||
|
float px, float sy1, float pw, float sy2,
|
||||||
|
float uMin, float uMax, float v1, float v2,
|
||||||
|
float ch, float texH, float z) {
|
||||||
|
int iz = 0;
|
||||||
|
for (float py = sy1; py < sy2; py += ch, iz++) {
|
||||||
|
float th = Math.min(ch, sy2 - py);
|
||||||
|
float vA = (iz & 1) == 0 ? v1 : v2;
|
||||||
|
float vB = (iz & 1) == 0 ? v1+th/texH : v2-th/texH;
|
||||||
|
n.attachChild(q(mat, px, py, pw, th, uMin, vA, uMax, vB, z));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static Geometry q(Material mat,
|
private static Geometry q(Material mat,
|
||||||
float x, float y, float w, float h,
|
float x, float y, float w, float h,
|
||||||
float uMin, float vMin, float uMax, float vMax,
|
float uMin, float vMin, float uMax, float vMax,
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user