aboutsummaryrefslogtreecommitdiff
path: root/common/src/main/java/dev/isxander/yacl3/gui/image
diff options
context:
space:
mode:
authorisxander <xander@isxander.dev>2024-04-11 18:43:06 +0100
committerisxander <xander@isxander.dev>2024-04-11 18:43:06 +0100
commit04fe933f4c24817100f3101f088accf55a621f8a (patch)
treefeff94ca3ab4484160e69a24f4ee38522381950e /common/src/main/java/dev/isxander/yacl3/gui/image
parent831b894fdb7fe3e173d81387c8f6a2402b8ccfa9 (diff)
downloadYetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.gz
YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.tar.bz2
YetAnotherConfigLib-04fe933f4c24817100f3101f088accf55a621f8a.zip
Extremely fragile and broken multiversion build with stonecutter
Diffstat (limited to 'common/src/main/java/dev/isxander/yacl3/gui/image')
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/image/ImageRenderer.java11
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererFactory.java24
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java127
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/image/YACLImageReloadListener.java102
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/image/impl/AnimatedDynamicTextureImage.java294
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/image/impl/DynamicTextureImage.java72
-rw-r--r--common/src/main/java/dev/isxander/yacl3/gui/image/impl/ResourceTextureImage.java56
7 files changed, 0 insertions, 686 deletions
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRenderer.java b/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRenderer.java
deleted file mode 100644
index d3fb4bf..0000000
--- a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRenderer.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package dev.isxander.yacl3.gui.image;
-
-import net.minecraft.client.gui.GuiGraphics;
-
-public interface ImageRenderer {
- int render(GuiGraphics graphics, int x, int y, int renderWidth, float tickDelta);
-
- void close();
-
- default void tick() {}
-}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererFactory.java b/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererFactory.java
deleted file mode 100644
index d9d2e2d..0000000
--- a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererFactory.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package dev.isxander.yacl3.gui.image;
-
-public interface ImageRendererFactory {
- /**
- * Prepares the image. This can be run off-thread,
- * and should NOT contain any GL calls whatsoever.
- */
- ImageSupplier prepareImage() throws Exception;
-
- default boolean requiresOffThreadPreparation() {
- return true;
- }
-
- interface ImageSupplier {
- ImageRenderer completeImage() throws Exception;
- }
-
- interface OnThread extends ImageRendererFactory {
- @Override
- default boolean requiresOffThreadPreparation() {
- return false;
- }
- }
-}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java b/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java
deleted file mode 100644
index 2f7ef50..0000000
--- a/common/src/main/java/dev/isxander/yacl3/gui/image/ImageRendererManager.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package dev.isxander.yacl3.gui.image;
-
-import com.mojang.blaze3d.systems.RenderSystem;
-import dev.isxander.yacl3.gui.image.impl.AnimatedDynamicTextureImage;
-import dev.isxander.yacl3.impl.utils.YACLConstants;
-import dev.isxander.yacl3.platform.YACLPlatform;
-import net.minecraft.client.Minecraft;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.packs.resources.Resource;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.*;
-import java.util.function.BiFunction;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-
-public class ImageRendererManager {
- private static final ExecutorService SINGLE_THREAD_EXECUTOR = Executors.newSingleThreadExecutor(task -> new Thread(task, "YACL Image Prep"));
-
- private static final Map<ResourceLocation, CompletableFuture<ImageRenderer>> IMAGE_CACHE = new ConcurrentHashMap<>();
- static final Map<ResourceLocation, ImageRenderer> PRELOADED_IMAGE_CACHE = new ConcurrentHashMap<>();
-
- static final List<PreloadedImageFactory> PRELOADED_IMAGE_FACTORIES = List.of(
- new PreloadedImageFactory(
- location -> location.getPath().endsWith(".webp"),
- AnimatedDynamicTextureImage::createWEBPFromResource
- ),
- new PreloadedImageFactory(
- location -> location.getPath().endsWith(".gif"),
- AnimatedDynamicTextureImage::createGIFFromResource
- )
- );
-
- public static <T extends ImageRenderer> Optional<T> getImage(ResourceLocation id) {
- if (PRELOADED_IMAGE_CACHE.containsKey(id)) {
- return Optional.of((T) PRELOADED_IMAGE_CACHE.get(id));
- }
-
- if (IMAGE_CACHE.containsKey(id)) {
- // warn developers if they don't put their webp/gif images `/textures` folder
- if (YACLPlatform.isDevelopmentEnv()) {
- if (PRELOADED_IMAGE_FACTORIES.stream().anyMatch(factory -> factory.predicate().test(id))) {
- YACLConstants.LOGGER.error("Image '{}' not preloaded. MAKE SURE THAT ALL YACL WEBP/GIF IMAGES ARE INSIDE YOUR ASSETS `/textures` FOLDER, ELSE THEY WILL NOT BE PRELOADED!!! THIS ERROR WILL NOT APPEAR IN PROD", id);
- }
- }
-
- return Optional.ofNullable((T) IMAGE_CACHE.get(id).getNow(null));
- }
-
- return Optional.empty();
- }
-
- @SuppressWarnings("unchecked")
- public static <T extends ImageRenderer> CompletableFuture<T> registerImage(ResourceLocation id, ImageRendererFactory factory) {
- if (IMAGE_CACHE.containsKey(id)) {
- return (CompletableFuture<T>) IMAGE_CACHE.get(id);
- }
-
- var future = new CompletableFuture<ImageRenderer>();
- IMAGE_CACHE.put(id, future);
-
- SINGLE_THREAD_EXECUTOR.submit(() -> {
- Supplier<Optional<ImageRendererFactory.ImageSupplier>> supplier =
- factory.requiresOffThreadPreparation()
- ? new CompletedSupplier<>(safelyPrepareFactory(id, factory))
- : () -> safelyPrepareFactory(id, factory);
-
- Minecraft.getInstance().execute(() -> completeImageFactory(id, supplier, future));
- });
-
- return (CompletableFuture<T>) future;
- }
-
- private static void completeImageFactory(ResourceLocation id, Supplier<Optional<ImageRendererFactory.ImageSupplier>> supplier, CompletableFuture<ImageRenderer> future) {
- RenderSystem.assertOnRenderThread();
-
- ImageRendererFactory.ImageSupplier completableImage = supplier.get().orElse(null);
- if (completableImage == null) {
- return;
- }
-
- // sanity check - this should never happen
- if (future.isDone()) {
- YACLConstants.LOGGER.error("Image '{}' was already completed", id);
- return;
- }
-
- ImageRenderer image;
- try {
- image = completableImage.completeImage();
- } catch (Exception e) {
- YACLConstants.LOGGER.error("Failed to create image '{}'", id, e);
- return;
- }
-
- future.complete(image);
- }
-
- public static void closeAll() {
- SINGLE_THREAD_EXECUTOR.shutdownNow();
- IMAGE_CACHE.values().removeIf(future -> {
- if (future.isDone()) {
- future.join().close();
- }
- return true;
- });
- }
-
- static Optional<ImageRendererFactory.ImageSupplier> safelyPrepareFactory(ResourceLocation id, ImageRendererFactory factory) {
- try {
- return Optional.of(factory.prepareImage());
- } catch (Exception e) {
- YACLConstants.LOGGER.error("Failed to prepare image '{}'", id, e);
- IMAGE_CACHE.remove(id);
- return Optional.empty();
- }
- }
-
- public record PreloadedImageFactory(Predicate<ResourceLocation> predicate, BiFunction<Resource, ResourceLocation, ImageRendererFactory> factory) {
- }
-
- private record CompletedSupplier<T>(T get) implements Supplier<T> {
- }
-
-}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/YACLImageReloadListener.java b/common/src/main/java/dev/isxander/yacl3/gui/image/YACLImageReloadListener.java
deleted file mode 100644
index bac8c56..0000000
--- a/common/src/main/java/dev/isxander/yacl3/gui/image/YACLImageReloadListener.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package dev.isxander.yacl3.gui.image;
-
-import dev.isxander.yacl3.impl.utils.YACLConstants;
-import net.minecraft.CrashReport;
-import net.minecraft.CrashReportCategory;
-import net.minecraft.ReportedException;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.packs.resources.PreparableReloadListener;
-import net.minecraft.server.packs.resources.Resource;
-import net.minecraft.server.packs.resources.ResourceManager;
-import net.minecraft.util.profiling.ProfilerFiller;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Executor;
-import java.util.function.Function;
-
-public class YACLImageReloadListener implements PreparableReloadListener {
- @Override
- public CompletableFuture<Void> reload(
- PreparationBarrier preparationBarrier,
- ResourceManager resourceManager,
- ProfilerFiller preparationsProfiler,
- ProfilerFiller reloadProfiler,
- Executor backgroundExecutor,
- Executor gameExecutor
- ) {
- YACLConstants.LOGGER.info("YACL is reloading images");
- Map<ResourceLocation, Resource> imageResources = resourceManager.listResources(
- "textures",
- location -> ImageRendererManager.PRELOADED_IMAGE_FACTORIES
- .stream()
- .anyMatch(factory -> factory.predicate().test(location))
- );
-
- // extreme mojang hackery.
- // for some reason this wait method needs to be called for the reload
- // instance to be marked as complete
- if (imageResources.isEmpty()) {
- preparationBarrier.wait(null);
- }
-
- List<CompletableFuture<?>> futures = new ArrayList<>(imageResources.size());
-
- for (Map.Entry<ResourceLocation, Resource> entry : imageResources.entrySet()) {
- ResourceLocation location = entry.getKey();
- Resource resource = entry.getValue();
-
- ImageRendererFactory imageFactory = ImageRendererManager.PRELOADED_IMAGE_FACTORIES
- .stream()
- .filter(factory -> factory.predicate().test(location))
- .map(factory -> factory.factory().apply(resource, location))
- .findAny()
- .orElseThrow();
-
- CompletableFuture<Optional<ImageRenderer>> imageFuture =
- CompletableFuture.supplyAsync(
- () -> ImageRendererManager.safelyPrepareFactory(
- location, imageFactory
- ),
- backgroundExecutor
- )
- .thenCompose(preparationBarrier::wait)
- .thenApplyAsync(imageSupplierOpt -> {
- if (imageSupplierOpt.isEmpty()) {
- return Optional.empty();
- }
- ImageRendererFactory.ImageSupplier supplier = imageSupplierOpt.get();
-
- ImageRenderer imageRenderer;
- try {
- imageRenderer = supplier.completeImage();
- } catch (Exception e) {
- YACLConstants.LOGGER.error("Failed to create image '{}'", location, e);
- return Optional.empty();
- }
-
- ImageRendererManager.PRELOADED_IMAGE_CACHE.put(location, imageRenderer);
-
- return Optional.of(imageRenderer);
- }, gameExecutor);
-
- futures.add(imageFuture);
-
- imageFuture.whenComplete((result, throwable) -> {
- if (throwable != null) {
- CrashReport crashReport = CrashReport.forThrowable(throwable, "Failed to load image");
- CrashReportCategory category = crashReport.addCategory("YACL Gui");
- category.setDetail("Image identifier", location.toString());
- throw new ReportedException(crashReport);
- }
- });
- }
-
- YACLConstants.LOGGER.info("YACL has found {} images", imageResources.size());
-
- return CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new));
- }
-}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/impl/AnimatedDynamicTextureImage.java b/common/src/main/java/dev/isxander/yacl3/gui/image/impl/AnimatedDynamicTextureImage.java
deleted file mode 100644
index 2136f56..0000000
--- a/common/src/main/java/dev/isxander/yacl3/gui/image/impl/AnimatedDynamicTextureImage.java
+++ /dev/null
@@ -1,294 +0,0 @@
-package dev.isxander.yacl3.gui.image.impl;
-
-import com.mojang.blaze3d.Blaze3D;
-import com.mojang.blaze3d.platform.GlConst;
-import com.mojang.blaze3d.platform.GlStateManager;
-import com.mojang.blaze3d.platform.NativeImage;
-import com.twelvemonkeys.imageio.plugins.webp.WebPImageReaderSpi;
-import dev.isxander.yacl3.debug.DebugProperties;
-import dev.isxander.yacl3.gui.image.ImageRendererFactory;
-import dev.isxander.yacl3.impl.utils.YACLConstants;
-import net.minecraft.CrashReport;
-import net.minecraft.CrashReportCategory;
-import net.minecraft.ReportedException;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiGraphics;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.server.packs.resources.Resource;
-import net.minecraft.server.packs.resources.ResourceManager;
-import net.minecraft.util.FastColor;
-
-import javax.imageio.ImageIO;
-import javax.imageio.ImageReader;
-import javax.imageio.metadata.IIOMetadata;
-import javax.imageio.metadata.IIOMetadataNode;
-import java.awt.*;
-import java.awt.image.BufferedImage;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.reflect.Field;
-import java.nio.file.Path;
-import java.util.List;
-import java.util.stream.IntStream;
-
-public class AnimatedDynamicTextureImage extends DynamicTextureImage {
- private int currentFrame;
- private double lastFrameTime;
-
- private final double[] frameDelays;
- private final int frameCount;
-
- private final int packCols, packRows;
- private final int frameWidth, frameHeight;
-
- public AnimatedDynamicTextureImage(NativeImage image, int frameWidth, int frameHeight, int frameCount, double[] frameDelayMS, int packCols, int packRows, ResourceLocation uniqueLocation) {
- super(image, uniqueLocation);
- this.frameWidth = frameWidth;
- this.frameHeight = frameHeight;
- this.frameCount = frameCount;
- this.frameDelays = frameDelayMS;
- this.packCols = packCols;
- this.packRows = packRows;
- }
-
- @Override
- public int render(GuiGraphics graphics, int x, int y, int renderWidth, float tickDelta) {
- if (image == null) return 0;
-
- float ratio = renderWidth / (float)frameWidth;
- int targetHeight = (int) (frameHeight * ratio);
-
- int currentCol = currentFrame % packCols;
- int currentRow = (int) Math.floor(currentFrame / (double)packCols);
-
- graphics.pose().pushPose();
- graphics.pose().translate(x, y, 0);
- graphics.pose().scale(ratio, ratio, 1);
-
- if (DebugProperties.IMAGE_FILTERING) {
- GlStateManager._texParameter(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MAG_FILTER, GlConst.GL_LINEAR);
- GlStateManager._texParameter(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MIN_FILTER, GlConst.GL_LINEAR);
- }
-
- graphics.blit(
- uniqueLocation,
- 0, 0,
- frameWidth * currentCol, frameHeight * currentRow,
- frameWidth, frameHeight,
- this.width, this.height
- );
- graphics.pose().popPose();
-
- if (frameCount > 1) {
- double timeMS = Blaze3D.getTime() * 1000;
- if (lastFrameTime == 0) lastFrameTime = timeMS;
- if (timeMS - lastFrameTime >= frameDelays[currentFrame]) {
- currentFrame++;
- lastFrameTime = timeMS;
- }
- if (currentFrame >= frameCount - 1)
- currentFrame = 0;
- }
-
- return targetHeight;
- }
-
- public static ImageRendererFactory createGIFFromTexture(ResourceLocation textureLocation) {
- return () -> {
- ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
- Resource resource = resourceManager.getResource(textureLocation).orElseThrow();
-
- return createGIFSupplier(resource.open(), textureLocation);
- };
- }
-
- public static ImageRendererFactory createGIFFromResource(Resource resource, ResourceLocation resourceLocation) {
- return () -> createGIFSupplier(resource.open(), resourceLocation);
- }
-
- public static ImageRendererFactory createGIFFromPath(Path path, ResourceLocation uniqueLocation) {
- return () -> createGIFSupplier(new FileInputStream(path.toFile()), uniqueLocation);
- }
-
- public static ImageRendererFactory createWEBPFromTexture(ResourceLocation textureLocation) {
- return () -> {
- ResourceManager resourceManager = Minecraft.getInstance().getResourceManager();
- Resource resource = resourceManager.getResource(textureLocation).orElseThrow();
-
- return createWEBPSupplier(resource.open(), textureLocation);
- };
- }
-
- public static ImageRendererFactory createWEBPFromResource(Resource resource, ResourceLocation resourceLocation) {
- return () -> createWEBPSupplier(resource.open(), resourceLocation);
- }
-
- public static ImageRendererFactory createWEBPFromPath(Path path, ResourceLocation uniqueLocation) {
- return () -> createWEBPSupplier(new FileInputStream(path.toFile()), uniqueLocation);
- }
-
- private static ImageRendererFactory.ImageSupplier createGIFSupplier(InputStream is, ResourceLocation uniqueLocation) {
- try (is) {
- ImageReader reader = ImageIO.getImageReadersBySuffix("gif").next();
- reader.setInput(ImageIO.createImageInputStream(is));
-
- AnimFrameProvider animFrameFunction = i -> {
- IIOMetadata metadata = reader.getImageMetadata(i);
- String metaFormatName = metadata.getNativeMetadataFormatName();
- IIOMetadataNode root = (IIOMetadataNode) metadata.getAsTree(metaFormatName);
- IIOMetadataNode graphicsControlExtensionNode = (IIOMetadataNode) root.getElementsByTagName("GraphicControlExtension").item(0);
- int delay = Integer.parseInt(graphicsControlExtensionNode.getAttribute("delayTime")) * 10;
-
- return new AnimFrame(delay, 0, 0);
- };
-
- return createFromImageReader(reader, animFrameFunction, uniqueLocation);
- } catch (Exception e) {
- CrashReport crashReport = CrashReport.forThrowable(e, "Failed to load GIF image");
- CrashReportCategory category = crashReport.addCategory("YACL Gui");
- category.setDetail("Image identifier", uniqueLocation.toString());
- throw new ReportedException(crashReport);
- }
- }
-
- private static ImageRendererFactory.ImageSupplier createWEBPSupplier(InputStream is, ResourceLocation uniqueLocation) {
- try (is) {
- ImageReader reader = new WebPImageReaderSpi().createReaderInstance();
- reader.setInput(ImageIO.createImageInputStream(is));
-
- int numImages = reader.getNumImages(true); // Force reading of all frames
- AnimFrameProvider animFrameFunction = i -> null;
- if (numImages > 1) {
- // WebP reader does not expose frame delay, prepare for reflection hell
- Class<?> webpReaderClass = Class.forName("com.twelvemonkeys.imageio.plugins.webp.WebPImageReader");
- Field framesField = webpReaderClass.getDeclaredField("frames");
- framesField.setAccessible(true);
- java.util.List<?> frames = (List<?>) framesField.get(reader);
-
- Class<?> animationFrameClass = Class.forName("com.twelvemonkeys.imageio.plugins.webp.AnimationFrame");
- Field durationField = animationFrameClass.getDeclaredField("duration");
- durationField.setAccessible(true);
- Field boundsField = animationFrameClass.getDeclaredField("bounds");
- boundsField.setAccessible(true);
-
- animFrameFunction = i -> {
- Rectangle bounds = (Rectangle) boundsField.get(frames.get(i));
- return new AnimFrame((int) durationField.get(frames.get(i)), bounds.x, bounds.y);
- };
- // that was fun
- }
-
- return createFromImageReader(reader, animFrameFunction, uniqueLocation);
- } catch (Throwable e) {
- CrashReport crashReport = CrashReport.forThrowable(e, "Failed to load WEBP image");
- CrashReportCategory category = crashReport.addCategory("YACL Gui");
- category.setDetail("Image identifier", uniqueLocation.toString());
- throw new ReportedException(crashReport);
- }
- }
-
- private static ImageRendererFactory.ImageSupplier createFromImageReader(ImageReader reader, AnimFrameProvider animationProvider, ResourceLocation uniqueLocation) throws Exception {
- if (reader.isSeekForwardOnly()) {
- throw new RuntimeException("Image reader is not seekable");
- }
-
- int frameCount = reader.getNumImages(true);
-
- // Because this is being backed into a texture atlas, we need a maximum dimension
- // so you can get the texture atlas size.
- // Smaller frames are given black borders
- int frameWidth = IntStream.range(0, frameCount).map(i -> {
- try {
- return reader.getWidth(i);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }).max().orElseThrow();
- int frameHeight = IntStream.range(0, frameCount).map(i -> {
- try {
- return reader.getHeight(i);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }).max().orElseThrow();
-
- // Packs the frames into an optimal 1:1 texture.
- // OpenGL can only have texture axis with a max of 32768 pixels,
- // and packing them to that length is not efficient, apparently.
- double ratio = frameWidth / (double)frameHeight;
- int cols = (int)Math.ceil(Math.sqrt(frameCount) / Math.sqrt(ratio));
- int rows = (int)Math.ceil(frameCount / (double)cols);
-
- NativeImage image = new NativeImage(NativeImage.Format.RGBA, frameWidth * cols, frameHeight * rows, false);
-
-// // Fill whole atlas with black, as each frame may have different dimensions
-// // that would cause borders of transparent pixels to appear around the frames
-// for (int x = 0; x < frameWidth * cols; x++) {
-// for (int y = 0; y < frameHeight * rows; y++) {
-// image.setPixelRGBA(x, y, 0xFF000000);
-// }
-// }
-
- BufferedImage bi = null;
- Graphics2D graphics = null;
-
- // each frame may have a different delay
- double[] frameDelays = new double[frameCount];
-
- for (int i = 0; i < frameCount; i++) {
- AnimFrame frame = animationProvider.get(i);
- if (frameCount > 1) // frame will be null if not animation
- frameDelays[i] = frame.durationMS;
-
- if (bi == null) {
- // first frame...
- bi = reader.read(i);
- graphics = bi.createGraphics();
- } else {
- // WebP reader sometimes provides delta frames, (only the pixels that changed since the last frame)
- // so instead of overwriting the image every frame, we draw delta frames on top of the previous frame
- // to keep a complete image.
- BufferedImage deltaFrame = reader.read(i);
- graphics.drawImage(deltaFrame, frame.xOffset, frame.yOffset, null);
- }
-
- // Each frame may have different dimensions, so we need to center them.
- int xOffset = (frameWidth - bi.getWidth()) / 2;
- int yOffset = (frameHeight - bi.getHeight()) / 2;
-
- for (int w = 0; w < bi.getWidth(); w++) {
- for (int h = 0; h < bi.getHeight(); h++) {
- int rgb = bi.getRGB(w, h);
- int r = FastColor.ARGB32.red(rgb);
- int g = FastColor.ARGB32.green(rgb);
- int b = FastColor.ARGB32.blue(rgb);
- int a = FastColor.ARGB32.alpha(rgb);
-
- int col = i % cols;
- int row = (int) Math.floor(i / (double)cols);
-
- image.setPixelRGBA(
- frameWidth * col + w + xOffset,
- frameHeight * row + h + yOffset,
- FastColor.ABGR32.color(a, b, g, r) // NativeImage uses ABGR for some reason
- );
- }
- }
- }
-
- if (graphics != null)
- graphics.dispose();
- reader.dispose();
-
- return () -> new AnimatedDynamicTextureImage(image, frameWidth, frameHeight, frameCount, frameDelays, cols, rows, uniqueLocation);
- }
-
- @FunctionalInterface
- private interface AnimFrameProvider {
- AnimFrame get(int frame) throws Exception;
- }
-
- private record AnimFrame(int durationMS, int xOffset, int yOffset) {}
-
-}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/impl/DynamicTextureImage.java b/common/src/main/java/dev/isxander/yacl3/gui/image/impl/DynamicTextureImage.java
deleted file mode 100644
index 2d2abb9..0000000
--- a/common/src/main/java/dev/isxander/yacl3/gui/image/impl/DynamicTextureImage.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package dev.isxander.yacl3.gui.image.impl;
-
-import com.mojang.blaze3d.platform.GlConst;
-import com.mojang.blaze3d.platform.GlStateManager;
-import com.mojang.blaze3d.platform.NativeImage;
-import com.mojang.blaze3d.systems.RenderSystem;
-import dev.isxander.yacl3.debug.DebugProperties;
-import dev.isxander.yacl3.gui.image.ImageRenderer;
-import dev.isxander.yacl3.gui.image.ImageRendererFactory;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.GuiGraphics;
-import net.minecraft.client.renderer.texture.DynamicTexture;
-import net.minecraft.client.renderer.texture.TextureManager;
-import net.minecraft.resources.ResourceLocation;
-
-import java.io.FileInputStream;
-import java.nio.file.Path;
-
-public class DynamicTextureImage implements ImageRenderer {
- protected static final TextureManager textureManager = Minecraft.getInstance().getTextureManager();
-
- protected NativeImage image;
- protected DynamicTexture texture;
- protected final ResourceLocation uniqueLocation;
- protected final int width, height;
-
- public DynamicTextureImage(NativeImage image, ResourceLocation location) {
- RenderSystem.assertOnRenderThread();
-
- this.image = image;
- this.texture = new DynamicTexture(image);
- this.uniqueLocation = location;
- textureManager.register(this.uniqueLocation, this.texture);
- this.width = image.getWidth();
- this.height = image.getHeight();
- }
-
- @Override
- public int render(GuiGraphics graphics, int x, int y, int renderWidth, float tickDelta) {
- if (image == null) return 0;
-
- float ratio = renderWidth / (float)this.width;
- int targetHeight = (int) (this.height * ratio);
-
- graphics.pose().pushPose();
- graphics.pose().translate(x, y, 0);
- graphics.pose().scale(ratio, ratio, 1);
-
- if (DebugProperties.IMAGE_FILTERING) {
- GlStateManager._texParameter(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MAG_FILTER, GlConst.GL_LINEAR);
- GlStateManager._texParameter(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MIN_FILTER, GlConst.GL_LINEAR);
- }
-
- graphics.blit(uniqueLocation, 0, 0, 0, 0, this.width, this.height, this.width, this.height);
-
- graphics.pose().popPose();
-
- return targetHeight;
- }
-
- @Override
- public void close() {
- image.close();
- image = null;
- texture = null;
- textureManager.release(uniqueLocation);
- }
-
- public static ImageRendererFactory fromPath(Path imagePath, ResourceLocation location) {
- return (ImageRendererFactory.OnThread) () -> () -> new DynamicTextureImage(NativeImage.read(new FileInputStream(imagePath.toFile())), location);
- }
-}
diff --git a/common/src/main/java/dev/isxander/yacl3/gui/image/impl/ResourceTextureImage.java b/common/src/main/java/dev/isxander/yacl3/gui/image/impl/ResourceTextureImage.java
deleted file mode 100644
index abbeec7..0000000
--- a/common/src/main/java/dev/isxander/yacl3/gui/image/impl/ResourceTextureImage.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package dev.isxander.yacl3.gui.image.impl;
-
-import com.mojang.blaze3d.platform.GlConst;
-import com.mojang.blaze3d.platform.GlStateManager;
-import dev.isxander.yacl3.debug.DebugProperties;
-import dev.isxander.yacl3.gui.image.ImageRenderer;
-import dev.isxander.yacl3.gui.image.ImageRendererFactory;
-import net.minecraft.client.gui.GuiGraphics;
-import net.minecraft.resources.ResourceLocation;
-
-public class ResourceTextureImage implements ImageRenderer {
- private final ResourceLocation location;
- private final int width, height;
- private final int textureWidth, textureHeight;
- private final float u, v;
-
- public ResourceTextureImage(ResourceLocation location, float u, float v, int width, int height, int textureWidth, int textureHeight) {
- this.location = location;
- this.width = width;
- this.height = height;
- this.textureWidth = textureWidth;
- this.textureHeight = textureHeight;
- this.u = u;
- this.v = v;
- }
-
- @Override
- public int render(GuiGraphics graphics, int x, int y, int renderWidth, float tickDelta) {
- float ratio = renderWidth / (float)this.width;
- int targetHeight = (int) (this.height * ratio);
-
- graphics.pose().pushPose();
- graphics.pose().translate(x, y, 0);
- graphics.pose().scale(ratio, ratio, 1);
-
- if (DebugProperties.IMAGE_FILTERING) {
- GlStateManager._texParameter(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MAG_FILTER, GlConst.GL_LINEAR);
- GlStateManager._texParameter(GlConst.GL_TEXTURE_2D, GlConst.GL_TEXTURE_MIN_FILTER, GlConst.GL_LINEAR);
- }
-
- graphics.blit(location, 0, 0, this.u, this.v, this.width, this.height, this.textureWidth, this.textureHeight);
-
- graphics.pose().popPose();
-
- return targetHeight;
- }
-
- @Override
- public void close() {
-
- }
-
- public static ImageRendererFactory createFactory(ResourceLocation location, float u, float v, int width, int height, int textureWidth, int textureHeight) {
- return (ImageRendererFactory.OnThread) () -> () -> new ResourceTextureImage(location, u, v, width, height, textureWidth, textureHeight);
- }
-}