/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.logging.LogUtils * it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue * org.lwjgl.system.MemoryUtil * org.slf4j.Logger */ package com.mojang.blaze3d.platform; import com.mojang.blaze3d.buffers.GpuBuffer; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.systems.CommandEncoder; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.textures.GpuTexture; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; import java.io.IOException; import java.io.InputStream; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; import java.nio.channels.SeekableByteChannel; import java.nio.file.Path; import java.util.Arrays; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.IntUnaryOperator; import net.minecraft.util.ARGB; import org.lwjgl.system.MemoryUtil; import org.slf4j.Logger; public class TextureUtil { private static final Logger LOGGER = LogUtils.getLogger(); public static final int MIN_MIPMAP_LEVEL = 0; private static final int DEFAULT_IMAGE_BUFFER_SIZE = 8192; private static final int[][] DIRECTIONS = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public static ByteBuffer readResource(InputStream inputStream) throws IOException { ReadableByteChannel channel = Channels.newChannel(inputStream); if (channel instanceof SeekableByteChannel) { SeekableByteChannel seekableChannel = (SeekableByteChannel)channel; return TextureUtil.readResource(channel, (int)seekableChannel.size() + 1); } return TextureUtil.readResource(channel, 8192); } private static ByteBuffer readResource(ReadableByteChannel channel, int expectedSize) throws IOException { ByteBuffer buffer = MemoryUtil.memAlloc((int)expectedSize); try { while (channel.read(buffer) != -1) { if (buffer.hasRemaining()) continue; buffer = MemoryUtil.memRealloc((ByteBuffer)buffer, (int)(buffer.capacity() * 2)); } buffer.flip(); return buffer; } catch (IOException e) { MemoryUtil.memFree((Buffer)buffer); throw e; } } public static void writeAsPNG(Path dir, String prefix, GpuTexture texture, int maxMipLevel, IntUnaryOperator pixelModifier) { RenderSystem.assertOnRenderThread(); int bufferLength = 0; for (int i = 0; i <= maxMipLevel; ++i) { bufferLength += texture.getFormat().pixelSize() * texture.getWidth(i) * texture.getHeight(i); } GpuBuffer buffer = RenderSystem.getDevice().createBuffer(() -> "Texture output buffer", 9, bufferLength); CommandEncoder commandEncoder = RenderSystem.getDevice().createCommandEncoder(); Runnable onCopyComplete = () -> { try (GpuBuffer.MappedView read = commandEncoder.mapBuffer(buffer, true, false);){ int offset = 0; for (int i = 0; i <= maxMipLevel; ++i) { int mipWidth = texture.getWidth(i); int mipHeight = texture.getHeight(i); try (NativeImage image = new NativeImage(mipWidth, mipHeight, false);){ for (int y = 0; y < mipHeight; ++y) { for (int x = 0; x < mipWidth; ++x) { int argb = read.data().getInt(offset + (x + y * mipWidth) * texture.getFormat().pixelSize()); image.setPixelABGR(x, y, pixelModifier.applyAsInt(argb)); } } Path target = dir.resolve(prefix + "_" + i + ".png"); image.writeToFile(target); LOGGER.debug("Exported png to: {}", (Object)target.toAbsolutePath()); } catch (IOException e) { LOGGER.debug("Unable to write: ", (Throwable)e); } offset += texture.getFormat().pixelSize() * mipWidth * mipHeight; } } buffer.close(); }; AtomicInteger completedCopies = new AtomicInteger(); int offset = 0; for (int i = 0; i <= maxMipLevel; ++i) { commandEncoder.copyTextureToBuffer(texture, buffer, offset, () -> { if (completedCopies.getAndIncrement() == maxMipLevel) { onCopyComplete.run(); } }, i); offset += texture.getFormat().pixelSize() * texture.getWidth(i) * texture.getHeight(i); } } public static Path getDebugTexturePath(Path root) { return root.resolve("screenshots").resolve("debug"); } public static Path getDebugTexturePath() { return TextureUtil.getDebugTexturePath(Path.of(".", new String[0])); } public static void solidify(NativeImage image) { int color; int y; int x; int width = image.getWidth(); int height = image.getHeight(); int[] nearestColor = new int[width * height]; int[] distances = new int[width * height]; Arrays.fill(distances, Integer.MAX_VALUE); IntArrayFIFOQueue queue = new IntArrayFIFOQueue(); for (x = 0; x < width; ++x) { for (y = 0; y < height; ++y) { color = image.getPixel(x, y); if (ARGB.alpha(color) == 0) continue; int packedCoordinates = TextureUtil.pack(x, y, width); distances[packedCoordinates] = 0; nearestColor[packedCoordinates] = color; queue.enqueue(packedCoordinates); } } while (!queue.isEmpty()) { int packedCoordinates = queue.dequeueInt(); int x2 = TextureUtil.x(packedCoordinates, width); int y2 = TextureUtil.y(packedCoordinates, width); for (int[] direction : DIRECTIONS) { int neighborX = x2 + direction[0]; int neighborY = y2 + direction[1]; int packedNeighborCoordinates = TextureUtil.pack(neighborX, neighborY, width); if (neighborX < 0 || neighborY < 0 || neighborX >= width || neighborY >= height || distances[packedNeighborCoordinates] <= distances[packedCoordinates] + 1) continue; distances[packedNeighborCoordinates] = distances[packedCoordinates] + 1; nearestColor[packedNeighborCoordinates] = nearestColor[packedCoordinates]; queue.enqueue(packedNeighborCoordinates); } } for (x = 0; x < width; ++x) { for (y = 0; y < height; ++y) { color = image.getPixel(x, y); if (ARGB.alpha(color) == 0) { image.setPixel(x, y, ARGB.color(0, nearestColor[TextureUtil.pack(x, y, width)])); continue; } image.setPixel(x, y, color); } } } private static int pack(int x, int y, int width) { return x + y * width; } private static int x(int packed, int width) { return packed % width; } private static int y(int packed, int width) { return packed / width; } }