MipmapGenerator.java

net.minecraft.client.renderer.texture.MipmapGenerator

信息

  • 全限定名:net.minecraft.client.renderer.texture.MipmapGenerator
  • 类型:public class
  • 包:net.minecraft.client.renderer.texture
  • 源码路径:src/main/java/net/minecraft/client/renderer/texture/MipmapGenerator.java
  • 起始行号:L12
  • 职责:

    TODO

字段/常量

  • ITEM_PREFIX

    • 类型: String
    • 修饰符: private static final
    • 源码定位: L13
    • 说明:

      TODO

  • ALPHA_CUTOFF

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L14
    • 说明:

      TODO

  • STRICT_ALPHA_CUTOFF

    • 类型: float
    • 修饰符: private static final
    • 源码定位: L15
    • 说明:

      TODO

内部类/嵌套类型

构造器

private MipmapGenerator() @ L17

  • 构造器名:MipmapGenerator
  • 源码定位:L17
  • 修饰符:private

参数:

说明:

TODO

方法

下面的方法块按源码顺序生成。

private static float alphaTestCoverage(NativeImage image, float alphaRef, float alphaScale) @ L20

  • 方法名:alphaTestCoverage
  • 源码定位:L20
  • 返回类型:float
  • 修饰符:private static

参数:

  • image: NativeImage
  • alphaRef: float
  • alphaScale: float

说明:

TODO

private static void scaleAlphaToCoverage(NativeImage image, float desiredCoverage, float alphaRef, float alphaCutoffBias) @ L53

  • 方法名:scaleAlphaToCoverage
  • 源码定位:L53
  • 返回类型:void
  • 修饰符:private static

参数:

  • image: NativeImage
  • desiredCoverage: float
  • alphaRef: float
  • alphaCutoffBias: float

说明:

TODO

public static NativeImage[] generateMipLevels(Identifier name, NativeImage[] currentMips, int newMipLevel, MipmapStrategy mipmapStrategy, float alphaCutoffBias, Transparency transparency) @ L94

  • 方法名:generateMipLevels
  • 源码定位:L94
  • 返回类型:NativeImage[]
  • 修饰符:public static

参数:

  • name: Identifier
  • currentMips: NativeImage[]
  • newMipLevel: int
  • mipmapStrategy: MipmapStrategy
  • alphaCutoffBias: float
  • transparency: Transparency

说明:

TODO

private static int darkenedAlphaBlend(int color1, int color2, int color3, int color4) @ L158

  • 方法名:darkenedAlphaBlend
  • 源码定位:L158
  • 返回类型:int
  • 修饰符:private static

参数:

  • color1: int
  • color2: int
  • color3: int
  • color4: int

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class MipmapGenerator {
    private static final String ITEM_PREFIX = "item/";
    private static final float ALPHA_CUTOFF = 0.5F;
    private static final float STRICT_ALPHA_CUTOFF = 0.3F;
 
    private MipmapGenerator() {
    }
 
    private static float alphaTestCoverage(NativeImage image, float alphaRef, float alphaScale) {
        int width = image.getWidth();
        int height = image.getHeight();
        float coverage = 0.0F;
        int subsample_count = 4;
 
        for (int y = 0; y < height - 1; y++) {
            for (int x = 0; x < width - 1; x++) {
                float alpha00 = Math.clamp(ARGB.alphaFloat(image.getPixel(x, y)) * alphaScale, 0.0F, 1.0F);
                float alpha10 = Math.clamp(ARGB.alphaFloat(image.getPixel(x + 1, y)) * alphaScale, 0.0F, 1.0F);
                float alpha01 = Math.clamp(ARGB.alphaFloat(image.getPixel(x, y + 1)) * alphaScale, 0.0F, 1.0F);
                float alpha11 = Math.clamp(ARGB.alphaFloat(image.getPixel(x + 1, y + 1)) * alphaScale, 0.0F, 1.0F);
                float texelCoverage = 0.0F;
 
                for (int subsample_y = 0; subsample_y < 4; subsample_y++) {
                    float fy = (subsample_y + 0.5F) / 4.0F;
 
                    for (int subsample_x = 0; subsample_x < 4; subsample_x++) {
                        float fx = (subsample_x + 0.5F) / 4.0F;
                        float alpha = alpha00 * (1.0F - fx) * (1.0F - fy) + alpha10 * fx * (1.0F - fy) + alpha01 * (1.0F - fx) * fy + alpha11 * fx * fy;
                        if (alpha > alphaRef) {
                            texelCoverage++;
                        }
                    }
                }
 
                coverage += texelCoverage / 16.0F;
            }
        }
 
        return coverage / ((width - 1) * (height - 1));
    }
 
    private static void scaleAlphaToCoverage(NativeImage image, float desiredCoverage, float alphaRef, float alphaCutoffBias) {
        float minAlphaScale = 0.0F;
        float maxAlphaScale = 4.0F;
        float alphaScale = 1.0F;
        float bestAlphaScale = 1.0F;
        float bestError = Float.MAX_VALUE;
        int width = image.getWidth();
        int height = image.getHeight();
 
        for (int i = 0; i < 5; i++) {
            float currentCoverage = alphaTestCoverage(image, alphaRef, alphaScale);
            float error = Math.abs(currentCoverage - desiredCoverage);
            if (error < bestError) {
                bestError = error;
                bestAlphaScale = alphaScale;
            }
 
            if (currentCoverage < desiredCoverage) {
                minAlphaScale = alphaScale;
            } else {
                if (!(currentCoverage > desiredCoverage)) {
                    break;
                }
 
                maxAlphaScale = alphaScale;
            }
 
            alphaScale = (minAlphaScale + maxAlphaScale) * 0.5F;
        }
 
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int pixel = image.getPixel(x, y);
                float alpha = ARGB.alphaFloat(pixel);
                alpha = alpha * bestAlphaScale + alphaCutoffBias + 0.025F;
                alpha = Math.clamp(alpha, 0.0F, 1.0F);
                image.setPixel(x, y, ARGB.color(alpha, pixel));
            }
        }
    }
 
    public static NativeImage[] generateMipLevels(
        Identifier name, NativeImage[] currentMips, int newMipLevel, MipmapStrategy mipmapStrategy, float alphaCutoffBias, Transparency transparency
    ) {
        if (mipmapStrategy == MipmapStrategy.AUTO) {
            mipmapStrategy = transparency.hasTransparent() ? MipmapStrategy.CUTOUT : MipmapStrategy.MEAN;
        }
 
        if (currentMips.length == 1 && !name.getPath().startsWith("item/")) {
            if (mipmapStrategy == MipmapStrategy.CUTOUT || mipmapStrategy == MipmapStrategy.STRICT_CUTOUT) {
                TextureUtil.solidify(currentMips[0]);
            } else if (mipmapStrategy == MipmapStrategy.DARK_CUTOUT) {
                TextureUtil.fillEmptyAreasWithDarkColor(currentMips[0]);
            }
        }
 
        if (newMipLevel + 1 <= currentMips.length) {
            return currentMips;
        } else {
            NativeImage[] result = new NativeImage[newMipLevel + 1];
            result[0] = currentMips[0];
            boolean isCutoutMip = mipmapStrategy == MipmapStrategy.CUTOUT
                || mipmapStrategy == MipmapStrategy.STRICT_CUTOUT
                || mipmapStrategy == MipmapStrategy.DARK_CUTOUT;
            float cutoutRef = mipmapStrategy == MipmapStrategy.STRICT_CUTOUT ? 0.3F : 0.5F;
            float originalCoverage = isCutoutMip ? alphaTestCoverage(currentMips[0], cutoutRef, 1.0F) : 0.0F;
 
            for (int level = 1; level <= newMipLevel; level++) {
                if (level < currentMips.length) {
                    result[level] = currentMips[level];
                } else {
                    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 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);
                            int color;
                            if (mipmapStrategy == MipmapStrategy.DARK_CUTOUT) {
                                color = darkenedAlphaBlend(color1, color2, color3, color4);
                            } else {
                                color = ARGB.meanLinear(color1, color2, color3, color4);
                            }
 
                            data.setPixel(x, y, color);
                        }
                    }
 
                    result[level] = data;
                }
 
                if (isCutoutMip) {
                    scaleAlphaToCoverage(result[level], originalCoverage, cutoutRef, alphaCutoffBias);
                }
            }
 
            return result;
        }
    }
 
    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));
        }
 
        aTotal /= 4.0F;
        rTotal /= 4.0F;
        gTotal /= 4.0F;
        bTotal /= 4.0F;
        return ARGB.color(
            ARGB.linearToSrgbChannel(aTotal), ARGB.linearToSrgbChannel(rTotal), ARGB.linearToSrgbChannel(gTotal), ARGB.linearToSrgbChannel(bTotal)
        );
    }
}

引用的其他类

  • NativeImage

    • 引用位置: 参数/构造调用/返回值
    • 关联成员: NativeImage()
  • TextureUtil

    • 引用位置: 方法调用
    • 关联成员: TextureUtil.fillEmptyAreasWithDarkColor(), TextureUtil.solidify()
  • Transparency

    • 引用位置: 参数
  • MipmapStrategy

    • 引用位置: 参数
  • Identifier

    • 引用位置: 参数
  • ARGB

    • 引用位置: 方法调用
    • 关联成员: ARGB.alpha(), ARGB.alphaFloat(), ARGB.blue(), ARGB.color(), ARGB.green(), ARGB.linearToSrgbChannel(), ARGB.meanLinear(), ARGB.red(), ARGB.srgbToLinearChannel()