TrueTypeGlyphProvider.java

com.mojang.blaze3d.font.TrueTypeGlyphProvider

信息

  • 全限定名:com.mojang.blaze3d.font.TrueTypeGlyphProvider
  • 类型:public class
  • 包:com.mojang.blaze3d.font
  • 源码路径:src/main/java/com/mojang/blaze3d/font/TrueTypeGlyphProvider.java
  • 起始行号:L28
  • 实现:GlyphProvider
  • 职责:

    TODO

字段/常量

  • fontMemory

    • 类型: ByteBuffer
    • 修饰符: private
    • 源码定位: L29
    • 说明:

      TODO

  • face

    • 类型: FT_Face
    • 修饰符: private
    • 源码定位: L30
    • 说明:

      TODO

  • oversample

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

      TODO

  • glyphs

    • 类型: CodepointMap<TrueTypeGlyphProvider.GlyphEntry>
    • 修饰符: private final
    • 源码定位: L32
    • 说明:

      TODO

内部类/嵌套类型

  • com.mojang.blaze3d.font.TrueTypeGlyphProvider.Glyph

    • 类型: class
    • 修饰符: private
    • 源码定位: L140
    • 说明:

      TODO

  • com.mojang.blaze3d.font.TrueTypeGlyphProvider.GlyphEntry

    • 类型: class
    • 修饰符: private static
    • 源码定位: L221
    • 说明:

      TODO

构造器

public TrueTypeGlyphProvider(ByteBuffer fontMemory, FT_Face face, float size, float oversample, float shiftX, float shiftY, String skip) @ L36

  • 构造器名:TrueTypeGlyphProvider
  • 源码定位:L36
  • 修饰符:public

参数:

  • fontMemory: ByteBuffer
  • face: FT_Face
  • size: float
  • oversample: float
  • shiftX: float
  • shiftY: float
  • skip: String

说明:

TODO

方法

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

public UnbakedGlyph getGlyph(int codepoint) @ L68

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

参数:

  • codepoint: int

说明:

TODO

private UnbakedGlyph getOrLoadGlyphInfo(int codepoint, TrueTypeGlyphProvider.GlyphEntry entry) @ L74

  • 方法名:getOrLoadGlyphInfo
  • 源码定位:L74
  • 返回类型:UnbakedGlyph
  • 修饰符:private

参数:

  • codepoint: int
  • entry: TrueTypeGlyphProvider.GlyphEntry

说明:

TODO

private UnbakedGlyph loadGlyph(int codepoint, FT_Face face, int index) @ L90

  • 方法名:loadGlyph
  • 源码定位:L90
  • 返回类型:UnbakedGlyph
  • 修饰符:private

参数:

  • codepoint: int
  • face: FT_Face
  • index: int

说明:

TODO

private FT_Face validateFontOpen() @ L112

  • 方法名:validateFontOpen
  • 源码定位:L112
  • 返回类型:FT_Face
  • 修饰符:private

参数:

说明:

TODO

public void close() @ L120

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

参数:

说明:

TODO

public IntSet getSupportedGlyphs() @ L134

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

参数:

说明:

TODO

代码

@OnlyIn(Dist.CLIENT)
public class TrueTypeGlyphProvider implements GlyphProvider {
    private @Nullable ByteBuffer fontMemory;
    private @Nullable FT_Face face;
    private final float oversample;
    private final CodepointMap<TrueTypeGlyphProvider.GlyphEntry> glyphs = new CodepointMap<>(
        TrueTypeGlyphProvider.GlyphEntry[]::new, TrueTypeGlyphProvider.GlyphEntry[][]::new
    );
 
    public TrueTypeGlyphProvider(ByteBuffer fontMemory, FT_Face face, float size, float oversample, float shiftX, float shiftY, String skip) {
        this.fontMemory = fontMemory;
        this.face = face;
        this.oversample = oversample;
        IntSet skipSet = new IntArraySet();
        skip.codePoints().forEach(skipSet::add);
        int pixelsPerEm = Math.round(size * oversample);
        FreeType.FT_Set_Pixel_Sizes(face, pixelsPerEm, pixelsPerEm);
        float transformX = shiftX * oversample;
        float transformY = -shiftY * oversample;
 
        try (MemoryStack stack = MemoryStack.stackPush()) {
            FT_Vector vector = FreeTypeUtil.setVector(FT_Vector.malloc(stack), transformX, transformY);
            FreeType.FT_Set_Transform(face, null, vector);
            IntBuffer indexPtr = stack.mallocInt(1);
            int codepoint = (int)FreeType.FT_Get_First_Char(face, indexPtr);
 
            while (true) {
                int index = indexPtr.get(0);
                if (index == 0) {
                    return;
                }
 
                if (!skipSet.contains(codepoint)) {
                    this.glyphs.put(codepoint, new TrueTypeGlyphProvider.GlyphEntry(index));
                }
 
                codepoint = (int)FreeType.FT_Get_Next_Char(face, codepoint, indexPtr);
            }
        }
    }
 
    @Override
    public @Nullable UnbakedGlyph getGlyph(int codepoint) {
        TrueTypeGlyphProvider.GlyphEntry entry = this.glyphs.get(codepoint);
        return entry != null ? this.getOrLoadGlyphInfo(codepoint, entry) : null;
    }
 
    private UnbakedGlyph getOrLoadGlyphInfo(int codepoint, TrueTypeGlyphProvider.GlyphEntry entry) {
        UnbakedGlyph result = entry.glyph;
        if (result == null) {
            FT_Face face = this.validateFontOpen();
            synchronized (face) {
                result = entry.glyph;
                if (result == null) {
                    result = this.loadGlyph(codepoint, face, entry.index);
                    entry.glyph = result;
                }
            }
        }
 
        return result;
    }
 
    private UnbakedGlyph loadGlyph(int codepoint, FT_Face face, int index) {
        int errorCode = FreeType.FT_Load_Glyph(face, index, 4194312);
        if (errorCode != 0) {
            FreeTypeUtil.assertError(errorCode, String.format(Locale.ROOT, "Loading glyph U+%06X", codepoint));
        }
 
        FT_GlyphSlot glyph = face.glyph();
        if (glyph == null) {
            throw new NullPointerException(String.format(Locale.ROOT, "Glyph U+%06X not initialized", codepoint));
        } else {
            float scaledAdvance = FreeTypeUtil.x(glyph.advance());
            FT_Bitmap bitmap = glyph.bitmap();
            int left = glyph.bitmap_left();
            int top = glyph.bitmap_top();
            int width = bitmap.width();
            int height = bitmap.rows();
            return (UnbakedGlyph)(width > 0 && height > 0
                ? new TrueTypeGlyphProvider.Glyph((float)left, (float)top, width, height, scaledAdvance, index)
                : new EmptyGlyph(scaledAdvance / this.oversample));
        }
    }
 
    private FT_Face validateFontOpen() {
        if (this.fontMemory != null && this.face != null) {
            return this.face;
        } else {
            throw new IllegalStateException("Provider already closed");
        }
    }
 
    @Override
    public void close() {
        if (this.face != null) {
            synchronized (FreeTypeUtil.LIBRARY_LOCK) {
                FreeTypeUtil.checkError(FreeType.FT_Done_Face(this.face), "Deleting face");
            }
 
            this.face = null;
        }
 
        MemoryUtil.memFree(this.fontMemory);
        this.fontMemory = null;
    }
 
    @Override
    public IntSet getSupportedGlyphs() {
        return this.glyphs.keySet();
    }
 
    @OnlyIn(Dist.CLIENT)
    private class Glyph implements UnbakedGlyph {
        private final int width;
        private final int height;
        private final float bearingX;
        private final float bearingY;
        private final GlyphInfo info;
        private final int index;
 
        private Glyph(float left, float top, int width, int height, float advance, int index) {
            Objects.requireNonNull(TrueTypeGlyphProvider.this);
            super();
            this.width = width;
            this.height = height;
            this.info = GlyphInfo.simple(advance / TrueTypeGlyphProvider.this.oversample);
            this.bearingX = left / TrueTypeGlyphProvider.this.oversample;
            this.bearingY = top / TrueTypeGlyphProvider.this.oversample;
            this.index = index;
        }
 
        @Override
        public GlyphInfo info() {
            return this.info;
        }
 
        @Override
        public BakedGlyph bake(UnbakedGlyph.Stitcher stitcher) {
            return stitcher.stitch(
                this.info,
                new GlyphBitmap() {
                    {
                        Objects.requireNonNull(Glyph.this);
                    }
 
                    @Override
                    public int getPixelWidth() {
                        return Glyph.this.width;
                    }
 
                    @Override
                    public int getPixelHeight() {
                        return Glyph.this.height;
                    }
 
                    @Override
                    public float getOversample() {
                        return TrueTypeGlyphProvider.this.oversample;
                    }
 
                    @Override
                    public float getBearingLeft() {
                        return Glyph.this.bearingX;
                    }
 
                    @Override
                    public float getBearingTop() {
                        return Glyph.this.bearingY;
                    }
 
                    @Override
                    public void upload(int x, int y, GpuTexture texture) {
                        FT_Face face = TrueTypeGlyphProvider.this.validateFontOpen();
 
                        try (NativeImage image = new NativeImage(NativeImage.Format.LUMINANCE, Glyph.this.width, Glyph.this.height, false)) {
                            if (image.copyFromFont(face, Glyph.this.index)) {
                                RenderSystem.getDevice()
                                    .createCommandEncoder()
                                    .writeToTexture(texture, image, 0, 0, x, y, Glyph.this.width, Glyph.this.height, 0, 0);
                            }
                        }
                    }
 
                    @Override
                    public boolean isColored() {
                        return false;
                    }
                }
            );
        }
    }
 
    @OnlyIn(Dist.CLIENT)
    private static class GlyphEntry {
        private final int index;
        private volatile @Nullable UnbakedGlyph glyph;
 
        private GlyphEntry(int index) {
            this.index = index;
        }
    }
}

引用的其他类

  • GlyphBitmap

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

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

    • 引用位置: 实现
  • UnbakedGlyph

    • 引用位置: 返回值
  • NativeImage

    • 引用位置: 构造调用
    • 关联成员: NativeImage()
  • RenderSystem

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

    • 引用位置: 字段
  • EmptyGlyph

    • 引用位置: 构造调用
    • 关联成员: EmptyGlyph()
  • FreeTypeUtil

    • 引用位置: 方法调用
    • 关联成员: FreeTypeUtil.assertError(), FreeTypeUtil.checkError(), FreeTypeUtil.setVector(), FreeTypeUtil.x()