BitmapProvider.java

net.minecraft.client.gui.font.providers.BitmapProvider

信息

  • 全限定名:net.minecraft.client.gui.font.providers.BitmapProvider
  • 类型:public class
  • 包:net.minecraft.client.gui.font.providers
  • 源码路径:src/main/java/net/minecraft/client/gui/font/providers/BitmapProvider.java
  • 起始行号:L33
  • 实现:GlyphProvider
  • 职责:

    TODO

字段/常量

  • LOGGER

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

      TODO

  • image

    • 类型: NativeImage
    • 修饰符: private final
    • 源码定位: L35
    • 说明:

      TODO

  • glyphs

    • 类型: CodepointMap<BitmapProvider.Glyph>
    • 修饰符: private final
    • 源码定位: L36
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.client.gui.font.providers.BitmapProvider.Definition

    • 类型: record
    • 修饰符: public
    • 源码定位: L59
    • 说明:

      TODO

  • net.minecraft.client.gui.font.providers.BitmapProvider.Glyph

    • 类型: record
    • 修饰符: private
    • 源码定位: L197
    • 说明:

      TODO

构造器

private BitmapProvider(NativeImage image, CodepointMap<BitmapProvider.Glyph> glyphs) @ L38

  • 构造器名:BitmapProvider
  • 源码定位:L38
  • 修饰符:private

参数:

  • image: NativeImage
  • glyphs: CodepointMap<BitmapProvider.Glyph>

说明:

TODO

方法

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

public void close() @ L43

  • 方法名:close
  • 源码定位:L43
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

public UnbakedGlyph getGlyph(int codepoint) @ L48

  • 方法名:getGlyph
  • 源码定位:L48
  • 返回类型:UnbakedGlyph
  • 修饰符:public

参数:

  • codepoint: int

说明:

TODO

public IntSet getSupportedGlyphs() @ L53

  • 方法名:getSupportedGlyphs
  • 源码定位:L53
  • 返回类型:IntSet
  • 修饰符:public

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class BitmapProvider implements GlyphProvider {
    private static final Logger LOGGER = LogUtils.getLogger();
    private final NativeImage image;
    private final CodepointMap<BitmapProvider.Glyph> glyphs;
 
    private BitmapProvider(NativeImage image, CodepointMap<BitmapProvider.Glyph> glyphs) {
        this.image = image;
        this.glyphs = glyphs;
    }
 
    @Override
    public void close() {
        this.image.close();
    }
 
    @Override
    public @Nullable UnbakedGlyph getGlyph(int codepoint) {
        return this.glyphs.get(codepoint);
    }
 
    @Override
    public IntSet getSupportedGlyphs() {
        return IntSets.unmodifiable(this.glyphs.keySet());
    }
 
    @OnlyIn(Dist.CLIENT)
    public record Definition(Identifier file, int height, int ascent, int[][] codepointGrid) implements GlyphProviderDefinition {
        private static final Codec<int[][]> CODEPOINT_GRID_CODEC = Codec.STRING.listOf().xmap(input -> {
            int lineCount = input.size();
            int[][] result = new int[lineCount][];
 
            for (int i = 0; i < lineCount; i++) {
                result[i] = input.get(i).codePoints().toArray();
            }
 
            return result;
        }, grid -> {
            List<String> result = new ArrayList<>(grid.length);
 
            for (int[] line : grid) {
                result.add(new String(line, 0, line.length));
            }
 
            return result;
        }).validate(BitmapProvider.Definition::validateDimensions);
        public static final MapCodec<BitmapProvider.Definition> CODEC = RecordCodecBuilder.<BitmapProvider.Definition>mapCodec(
                i -> i.group(
                        Identifier.CODEC.fieldOf("file").forGetter(BitmapProvider.Definition::file),
                        Codec.INT.optionalFieldOf("height", 8).forGetter(BitmapProvider.Definition::height),
                        Codec.INT.fieldOf("ascent").forGetter(BitmapProvider.Definition::ascent),
                        CODEPOINT_GRID_CODEC.fieldOf("chars").forGetter(BitmapProvider.Definition::codepointGrid)
                    )
                    .apply(i, BitmapProvider.Definition::new)
            )
            .validate(BitmapProvider.Definition::validate);
 
        private static DataResult<int[][]> validateDimensions(int[][] grid) {
            int lineCount = grid.length;
            if (lineCount == 0) {
                return DataResult.error(() -> "Expected to find data in codepoint grid");
            } else {
                int[] firstLine = grid[0];
                int lineWidth = firstLine.length;
                if (lineWidth == 0) {
                    return DataResult.error(() -> "Expected to find data in codepoint grid");
                } else {
                    for (int i = 1; i < lineCount; i++) {
                        int[] line = grid[i];
                        if (line.length != lineWidth) {
                            return DataResult.error(
                                () -> "Lines in codepoint grid have to be the same length (found: "
                                    + line.length
                                    + " codepoints, expected: "
                                    + lineWidth
                                    + "), pad with \\u0000"
                            );
                        }
                    }
 
                    return DataResult.success(grid);
                }
            }
        }
 
        private static DataResult<BitmapProvider.Definition> validate(BitmapProvider.Definition builder) {
            return builder.ascent > builder.height
                ? DataResult.error(() -> "Ascent " + builder.ascent + " higher than height " + builder.height)
                : DataResult.success(builder);
        }
 
        @Override
        public GlyphProviderType type() {
            return GlyphProviderType.BITMAP;
        }
 
        @Override
        public Either<GlyphProviderDefinition.Loader, GlyphProviderDefinition.Reference> unpack() {
            return Either.left(this::load);
        }
 
        private GlyphProvider load(ResourceManager resourceManager) throws IOException {
            Identifier texture = this.file.withPrefix("textures/");
 
            BitmapProvider var22;
            try (InputStream resource = resourceManager.open(texture)) {
                NativeImage image = NativeImage.read(NativeImage.Format.RGBA, resource);
                int w = image.getWidth();
                int h = image.getHeight();
                int glyphWidth = w / this.codepointGrid[0].length;
                int glyphHeight = h / this.codepointGrid.length;
                float pixelScale = (float)this.height / glyphHeight;
                CodepointMap<BitmapProvider.Glyph> charMap = new CodepointMap<>(BitmapProvider.Glyph[]::new, BitmapProvider.Glyph[][]::new);
 
                for (int slotY = 0; slotY < this.codepointGrid.length; slotY++) {
                    int linePos = 0;
 
                    for (int c : this.codepointGrid[slotY]) {
                        int slotX = linePos++;
                        if (c != 0) {
                            int actualGlyphWidth = this.getActualGlyphWidth(image, glyphWidth, glyphHeight, slotX, slotY);
                            BitmapProvider.Glyph prev = charMap.put(
                                c,
                                new BitmapProvider.Glyph(
                                    pixelScale,
                                    image,
                                    slotX * glyphWidth,
                                    slotY * glyphHeight,
                                    glyphWidth,
                                    glyphHeight,
                                    (int)(0.5 + actualGlyphWidth * pixelScale) + 1,
                                    this.ascent
                                )
                            );
                            if (prev != null) {
                                BitmapProvider.LOGGER.warn("Codepoint '{}' declared multiple times in {}", Integer.toHexString(c), texture);
                            }
                        }
                    }
                }
 
                var22 = new BitmapProvider(image, charMap);
            }
 
            return var22;
        }
 
        private int getActualGlyphWidth(NativeImage image, int glyphWidth, int glyphHeight, int xGlyph, int yGlyph) {
            int width;
            for (width = glyphWidth - 1; width >= 0; width--) {
                int xPixel = xGlyph * glyphWidth + width;
 
                for (int y = 0; y < glyphHeight; y++) {
                    int yPixel = yGlyph * glyphHeight + y;
                    if (image.getLuminanceOrAlpha(xPixel, yPixel) != 0) {
                        return width + 1;
                    }
                }
            }
 
            return width + 1;
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private record Glyph(float scale, NativeImage image, int offsetX, int offsetY, int width, int height, int advance, int ascent) implements UnbakedGlyph {
        @Override
        public GlyphInfo info() {
            return GlyphInfo.simple(this.advance);
        }
 
        @Override
        public BakedGlyph bake(UnbakedGlyph.Stitcher stitcher) {
            return stitcher.stitch(
                this.info(),
                new GlyphBitmap() {
                    {
                        Objects.requireNonNull(Glyph.this);
                    }
 
                    @Override
                    public float getOversample() {
                        return 1.0F / Glyph.this.scale;
                    }
 
                    @Override
                    public int getPixelWidth() {
                        return Glyph.this.width;
                    }
 
                    @Override
                    public int getPixelHeight() {
                        return Glyph.this.height;
                    }
 
                    @Override
                    public float getBearingTop() {
                        return Glyph.this.ascent;
                    }
 
                    @Override
                    public void upload(int x, int y, GpuTexture texture) {
                        RenderSystem.getDevice()
                            .createCommandEncoder()
                            .writeToTexture(texture, Glyph.this.image, 0, 0, x, y, Glyph.this.width, Glyph.this.height, Glyph.this.offsetX, Glyph.this.offsetY);
                    }
 
                    @Override
                    public boolean isColored() {
                        return Glyph.this.image.format().components() > 1;
                    }
                }
            );
        }
    }
}

引用的其他类

  • GlyphBitmap

    • 引用位置: 构造调用
    • 关联成员: GlyphBitmap()
  • GlyphInfo

    • 引用位置: 方法调用
    • 关联成员: GlyphInfo.simple()
  • GlyphProvider

    • 引用位置: 实现
  • UnbakedGlyph

    • 引用位置: 返回值
  • NativeImage

    • 引用位置: 参数/字段/方法调用
    • 关联成员: NativeImage.read()
  • RenderSystem

    • 引用位置: 方法调用
    • 关联成员: RenderSystem.getDevice()
  • CodepointMap

    • 引用位置: 参数/字段