/* * Decompiled with CFR 0.152. */ package net.minecraft.client.renderer.texture; import com.mojang.blaze3d.platform.NativeImage; import com.mojang.blaze3d.platform.TextureUtil; import net.minecraft.client.renderer.texture.MipmapStrategy; import net.minecraft.resources.Identifier; import net.minecraft.util.ARGB; public class MipmapGenerator { private static final String ITEM_PREFIX = "item/"; private static final float ALPHA_CUTOFF = 0.2f; private static final float STRICT_ALPHA_CUTOFF = 0.6f; private static final int ALPHA_CUTOUT_CUTOFF = 96; private MipmapGenerator() { } public static NativeImage[] generateMipLevels(Identifier name, NativeImage[] currentMips, int newMipLevel, MipmapStrategy mipmapStrategy) { if (newMipLevel + 1 <= currentMips.length) { return currentMips; } NativeImage[] result = new NativeImage[newMipLevel + 1]; if (mipmapStrategy == MipmapStrategy.AUTO) { if (name.getPath().startsWith(ITEM_PREFIX)) { mipmapStrategy = MipmapStrategy.STRICT_CUTOUT; } else { MipmapStrategy mipmapStrategy2 = mipmapStrategy = MipmapGenerator.hasTransparentPixel(currentMips[0]) ? MipmapStrategy.CUTOUT : MipmapStrategy.MEAN; } } if (currentMips.length == 1 && (mipmapStrategy == MipmapStrategy.CUTOUT || mipmapStrategy == MipmapStrategy.STRICT_CUTOUT)) { TextureUtil.solidify(currentMips[0]); } result[0] = currentMips[0]; for (int level = 1; level <= newMipLevel; ++level) { if (level < currentMips.length) { result[level] = currentMips[level]; continue; } NativeImage lastData = result[level - 1]; NativeImage data = new NativeImage(lastData.getWidth() >> 1, lastData.getHeight() >> 1, false); int width = data.getWidth(); int height = data.getHeight(); for (int x = 0; x < width; ++x) { for (int y = 0; y < height; ++y) { int color; if (mipmapStrategy == MipmapStrategy.MEAN || mipmapStrategy == MipmapStrategy.DARK_CUTOUT) { int color1 = lastData.getPixel(x * 2 + 0, y * 2 + 0); int color2 = lastData.getPixel(x * 2 + 1, y * 2 + 0); int color3 = lastData.getPixel(x * 2 + 0, y * 2 + 1); int color4 = lastData.getPixel(x * 2 + 1, y * 2 + 1); color = mipmapStrategy == MipmapStrategy.DARK_CUTOUT ? MipmapGenerator.darkenedAlphaBlend(color1, color2, color3, color4) : ARGB.meanLinear(color1, color2, color3, color4); } else { color = MipmapGenerator.alphaBlend(x, y, result[0], level, mipmapStrategy); } data.setPixel(x, y, color); } } result[level] = data; } return result; } private static boolean hasTransparentPixel(NativeImage image) { for (int x = 0; x < image.getWidth(); ++x) { for (int y = 0; y < image.getHeight(); ++y) { if (ARGB.alpha(image.getPixel(x, y)) != 0) continue; return true; } } return false; } private static int darkenedAlphaBlend(int color1, int color2, int color3, int color4) { float aTotal = 0.0f; float rTotal = 0.0f; float gTotal = 0.0f; float bTotal = 0.0f; if (ARGB.alpha(color1) != 0) { aTotal += ARGB.srgbToLinearChannel(ARGB.alpha(color1)); rTotal += ARGB.srgbToLinearChannel(ARGB.red(color1)); gTotal += ARGB.srgbToLinearChannel(ARGB.green(color1)); bTotal += ARGB.srgbToLinearChannel(ARGB.blue(color1)); } if (ARGB.alpha(color2) != 0) { aTotal += ARGB.srgbToLinearChannel(ARGB.alpha(color2)); rTotal += ARGB.srgbToLinearChannel(ARGB.red(color2)); gTotal += ARGB.srgbToLinearChannel(ARGB.green(color2)); bTotal += ARGB.srgbToLinearChannel(ARGB.blue(color2)); } if (ARGB.alpha(color3) != 0) { aTotal += ARGB.srgbToLinearChannel(ARGB.alpha(color3)); rTotal += ARGB.srgbToLinearChannel(ARGB.red(color3)); gTotal += ARGB.srgbToLinearChannel(ARGB.green(color3)); bTotal += ARGB.srgbToLinearChannel(ARGB.blue(color3)); } if (ARGB.alpha(color4) != 0) { aTotal += ARGB.srgbToLinearChannel(ARGB.alpha(color4)); rTotal += ARGB.srgbToLinearChannel(ARGB.red(color4)); gTotal += ARGB.srgbToLinearChannel(ARGB.green(color4)); bTotal += ARGB.srgbToLinearChannel(ARGB.blue(color4)); } rTotal /= 4.0f; gTotal /= 4.0f; bTotal /= 4.0f; int finalAlpha = ARGB.linearToSrgbChannel(aTotal /= 4.0f); if (finalAlpha < 96) { finalAlpha = 0; } return ARGB.color(finalAlpha, ARGB.linearToSrgbChannel(rTotal), ARGB.linearToSrgbChannel(gTotal), ARGB.linearToSrgbChannel(bTotal)); } private static int alphaBlend(int x, int y, NativeImage originalImage, int level, MipmapStrategy mipmapStrategy) { float resultAlpha; float[] accumulated = new float[7]; int size = 1 << level; for (int xOrig = x * size; xOrig < x * size + size; ++xOrig) { for (int yOrig = y * size; yOrig < y * size + size; ++yOrig) { MipmapGenerator.accumulate(originalImage.getPixel(xOrig, yOrig), accumulated); } } float alphaTotal = accumulated[0]; float resultRed = accumulated[1] / alphaTotal; float resultGreen = accumulated[2] / alphaTotal; float resultBlue = accumulated[3] / alphaTotal; alphaTotal /= (float)(size * size); float f = mipmapStrategy == MipmapStrategy.STRICT_CUTOUT ? 0.6f : 0.2f; if (alphaTotal < f) { resultAlpha = 0.0f; resultRed = accumulated[4] / (float)(size * size); resultGreen = accumulated[5] / (float)(size * size); resultBlue = accumulated[6] / (float)(size * size); } else { resultAlpha = 1.0f; } return ARGB.color(resultAlpha, ARGB.color(ARGB.linearToSrgbChannel(resultRed), ARGB.linearToSrgbChannel(resultGreen), ARGB.linearToSrgbChannel(resultBlue))); } private static void accumulate(int color, float[] accumulated) { float alpha = ARGB.alphaFloat(color); accumulated[0] = accumulated[0] + alpha; float red = ARGB.srgbToLinearChannel(ARGB.red(color)); accumulated[1] = accumulated[1] + red * alpha; accumulated[4] = accumulated[4] + red; float green = ARGB.srgbToLinearChannel(ARGB.green(color)); accumulated[2] = accumulated[2] + green * alpha; accumulated[5] = accumulated[5] + green; float blue = ARGB.srgbToLinearChannel(ARGB.blue(color)); accumulated[3] = accumulated[3] + blue * alpha; accumulated[6] = accumulated[6] + blue; } }