package xyz.marsavic.gfxlab.gui; import com.google.common.collect.ImmutableList; import javafx.embed.swing.SwingFXUtils; import javafx.scene.image.Image; import javafx.scene.image.PixelFormat; import javafx.scene.image.WritableImage; import javafx.scene.input.Clipboard; import javafx.scene.input.ClipboardContent; import javafx.stage.FileChooser; import xyz.marsavic.functions.interfaces.A1; import xyz.marsavic.functions.interfaces.A2; import xyz.marsavic.geometry.Vector; import xyz.marsavic.gfxlab.Color; import xyz.marsavic.gfxlab.Matrix; import xyz.marsavic.gfxlab.MatrixData; import xyz.marsavic.gfxlab.MatrixInts; import xyz.marsavic.resources.ResourceManagerMap; import xyz.marsavic.random.RNG; import xyz.marsavic.time.Profiler; import xyz.marsavic.utils.Utils; import javax.imageio.ImageIO; import java.io.File; import java.io.IOException; import java.nio.IntBuffer; import java.util.Collection; import java.util.Collections; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Future; import java.util.function.IntConsumer; import java.util.stream.IntStream; public class UtilsGL { private static final Set profilers = Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>())); public static Profiler profiler(Object object, String description) { String name = String.format("%08x", System.identityHashCode(object)) + " " + object.getClass().getSimpleName() + " " + description; Profiler profiler = new Profiler(name); profilers.add(profiler); return profiler; } /** * Live profilers, but not a live collection. * The returned collection is immutable and contains only the profilers present at the moment of calling. */ public static Collection profilers() { synchronized (profilers) { return ImmutableList.copyOf(profilers); } } // JavaFX helpers static final PixelFormat pixelFormat = PixelFormat.getIntArgbPreInstance(); public static Image writeRawImageToImage(MatrixInts rawImage) { int sx = rawImage.width(); int sy = rawImage.height(); WritableImage image = new WritableImage(sx, sy); writeRawImageToImage(image, rawImage); return image; } public static void writeRawImageToImage(WritableImage outImage, Matrix inRawImage) { int sx = inRawImage.size().xInt(); int sy = inRawImage.size().yInt(); if (inRawImage instanceof MatrixInts matrixInts) { outImage.getPixelWriter().setPixels(0, 0, sx, sy, pixelFormat, matrixInts.array(), 0, sx); } else { // TODO throw new UnsupportedOperationException("To be implemented..."); } } public static Vector imageSize(Image image) { return Vector.xy(image.getWidth(), image.getHeight()); } public static WritableImage createWritableImage(Vector size) { return new WritableImage(size.xInt(), size.yInt()); } public static void saveImageToFileWithDialog(Image image) { FileChooser fileChooser = new FileChooser(); fileChooser.setTitle("Export Image"); fileChooser.setInitialDirectory(new File(".")); fileChooser.getExtensionFilters().addAll( new FileChooser.ExtensionFilter("Image Files", "*.png"), new FileChooser.ExtensionFilter("All Files", "*.*") ); File file = fileChooser.showSaveDialog(null); if (file != null) { try { ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file); } catch (IOException e) { e.printStackTrace(); } } } public static void copyImageToClipboard(Image image) { ClipboardContent content = new ClipboardContent(); content.putImage(image); Clipboard.getSystemClipboard().setContent(content); } // --- Parallel utils ------- public static final ExecutorService pool; public static final int parallelism; static { int p = ForkJoinPool.getCommonPoolParallelism(); try { boolean obsRunning = false; obsRunning |= ProcessHandle.allProcesses().anyMatch(ph -> ph.info().command().orElse("").contains("obs64")); // Windows obsRunning |= !Utils.runCommand("top -b -n 1 | grep \" obs\"").isEmpty(); // Linux obsRunning |= true; if (obsRunning) { p -= 3; } } catch (Exception e) { e.printStackTrace(); } parallelism = 3; pool = new ForkJoinPool(parallelism); } public static void parallel(int iFrom, int iTo, IntConsumer action) { Future f = pool.submit(() -> { try { IntStream.range(iFrom, iTo).parallel().forEach(action); } catch (Exception e) { e.printStackTrace(); } }); while (true) { try { f.get(); break; } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } public static void parallel(int iTo, IntConsumer action) { parallel(0, iTo, action); } public static void parallelY(Vector size, IntConsumer action) { parallel(size.yInt(), action); } public static void parallelY(Vector size, A2 action) { parallelY(size, y -> { for (int x = 0; x < size.xInt(); x++) { action.execute(x, y); } }); } public static void parallel(Vector size, A1 action) { parallelY(size, y -> { for (int x = 0; x < size.xInt(); x++) { action.execute(Vector.xy(x, y)); } }); } public static RNG[] rngArray(int n, long seed) { RNG seeds = new RNG(seed); RNG[] rngs = new RNG[n]; for (int i = 0; i < n; i++) { rngs[i] = new RNG(seeds.nextLong()); } return rngs; } public static RNG[] rngArray(int n) { return rngArray(n, new RNG().nextLong()); } public static final ResourceManagerMap> matricesColor = new ResourceManagerMap<>( MatrixData::new, (m, sz) -> m.fill(Color.BLACK) ); public static final ResourceManagerMap> matricesInt = new ResourceManagerMap<>( MatrixInts::new, (m, sz) -> m.fill(0) ); }