UnihexProvider.java
net.minecraft.client.gui.font.providers.UnihexProvider
信息
- 全限定名:net.minecraft.client.gui.font.providers.UnihexProvider
- 类型:public class
- 包:net.minecraft.client.gui.font.providers
- 源码路径:src/main/java/net/minecraft/client/gui/font/providers/UnihexProvider.java
- 起始行号:L40
- 实现:GlyphProvider
- 职责:
TODO
字段/常量
-
LOGGER- 类型:
Logger - 修饰符:
private static final - 源码定位:
L41 - 说明:
TODO
- 类型:
-
GLYPH_HEIGHT- 类型:
int - 修饰符:
private static final - 源码定位:
L42 - 说明:
TODO
- 类型:
-
DIGITS_PER_BYTE- 类型:
int - 修饰符:
private static final - 源码定位:
L43 - 说明:
TODO
- 类型:
-
DIGITS_FOR_WIDTH_8- 类型:
int - 修饰符:
private static final - 源码定位:
L44 - 说明:
TODO
- 类型:
-
DIGITS_FOR_WIDTH_16- 类型:
int - 修饰符:
private static final - 源码定位:
L45 - 说明:
TODO
- 类型:
-
DIGITS_FOR_WIDTH_24- 类型:
int - 修饰符:
private static final - 源码定位:
L46 - 说明:
TODO
- 类型:
-
DIGITS_FOR_WIDTH_32- 类型:
int - 修饰符:
private static final - 源码定位:
L47 - 说明:
TODO
- 类型:
-
glyphs- 类型:
CodepointMap<UnihexProvider.Glyph> - 修饰符:
private final - 源码定位:
L48 - 说明:
TODO
- 类型:
内部类/嵌套类型
-
net.minecraft.client.gui.font.providers.UnihexProvider.ByteContents- 类型:
record - 修饰符:
private - 源码定位:
L169 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.Definition- 类型:
class - 修饰符:
public static - 源码定位:
L196 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.Dimensions- 类型:
record - 修饰符:
public - 源码定位:
L275 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.Glyph- 类型:
record - 修饰符:
private - 源码定位:
L303 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.IntContents- 类型:
record - 修饰符:
private - 源码定位:
L377 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.LineData- 类型:
interface - 修饰符:
public - 源码定位:
L429 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.OverrideRange- 类型:
record - 修饰符:
private - 源码定位:
L462 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.ReaderOutput- 类型:
interface - 修饰符:
public - 源码定位:
L478 - 说明:
TODO
- 类型:
-
net.minecraft.client.gui.font.providers.UnihexProvider.ShortContents- 类型:
record - 修饰符:
private - 源码定位:
L483 - 说明:
TODO
- 类型:
构造器
private UnihexProvider(CodepointMap<UnihexProvider.Glyph> glyphs) @ L50
- 构造器名:UnihexProvider
- 源码定位:L50
- 修饰符:private
参数:
- glyphs: CodepointMap<UnihexProvider.Glyph>
说明:
TODO
方法
下面的方法块按源码顺序生成。
public UnbakedGlyph getGlyph(int codepoint) @ L54
- 方法名:getGlyph
- 源码定位:L54
- 返回类型:UnbakedGlyph
- 修饰符:public
参数:
- codepoint: int
说明:
TODO
public IntSet getSupportedGlyphs() @ L59
- 方法名:getSupportedGlyphs
- 源码定位:L59
- 返回类型:IntSet
- 修饰符:public
参数:
- 无
说明:
TODO
static void unpackBitsToBytes(IntBuffer output, int value, int left, int right) @ L64
- 方法名:unpackBitsToBytes
- 源码定位:L64
- 返回类型:void
- 修饰符:static
参数:
- output: IntBuffer
- value: int
- left: int
- right: int
说明:
TODO
private static void unpackBitsToBytes(IntBuffer output, UnihexProvider.LineData data, int left, int right) @ L79
- 方法名:unpackBitsToBytes
- 源码定位:L79
- 返回类型:void
- 修饰符:private static
参数:
- output: IntBuffer
- data: UnihexProvider.LineData
- left: int
- right: int
说明:
TODO
static void readFromStream(InputStream input, UnihexProvider.ReaderOutput output) @ L86
- 方法名:readFromStream
- 源码定位:L86
- 返回类型:void
- 修饰符:static
参数:
- input: InputStream
- output: UnihexProvider.ReaderOutput
说明:
TODO
private static int decodeHex(int line, ByteList input, int index) @ L127
- 方法名:decodeHex
- 源码定位:L127
- 返回类型:int
- 修饰符:private static
参数:
- line: int
- input: ByteList
- index: int
说明:
TODO
private static int decodeHex(int line, byte b) @ L131
- 方法名:decodeHex
- 源码定位:L131
- 返回类型:int
- 修饰符:private static
参数:
- line: int
- b: byte
说明:
TODO
private static boolean copyUntil(InputStream input, ByteList output, int delimiter) @ L153
- 方法名:copyUntil
- 源码定位:L153
- 返回类型:boolean
- 修饰符:private static
参数:
- input: InputStream
- output: ByteList
- delimiter: int
说明:
TODO
代码
@OnlyIn(Dist.CLIENT)
public class UnihexProvider implements GlyphProvider {
private static final Logger LOGGER = LogUtils.getLogger();
private static final int GLYPH_HEIGHT = 16;
private static final int DIGITS_PER_BYTE = 2;
private static final int DIGITS_FOR_WIDTH_8 = 32;
private static final int DIGITS_FOR_WIDTH_16 = 64;
private static final int DIGITS_FOR_WIDTH_24 = 96;
private static final int DIGITS_FOR_WIDTH_32 = 128;
private final CodepointMap<UnihexProvider.Glyph> glyphs;
private UnihexProvider(CodepointMap<UnihexProvider.Glyph> glyphs) {
this.glyphs = glyphs;
}
@Override
public @Nullable UnbakedGlyph getGlyph(int codepoint) {
return this.glyphs.get(codepoint);
}
@Override
public IntSet getSupportedGlyphs() {
return this.glyphs.keySet();
}
@VisibleForTesting
static void unpackBitsToBytes(IntBuffer output, int value, int left, int right) {
int startBit = 32 - left - 1;
int endBit = 32 - right - 1;
for (int i = startBit; i >= endBit; i--) {
if (i < 32 && i >= 0) {
boolean isSet = (value >> i & 1) != 0;
output.put(isSet ? -1 : 0);
} else {
output.put(0);
}
}
}
private static void unpackBitsToBytes(IntBuffer output, UnihexProvider.LineData data, int left, int right) {
for (int i = 0; i < 16; i++) {
int line = data.line(i);
unpackBitsToBytes(output, line, left, right);
}
}
@VisibleForTesting
static void readFromStream(InputStream input, UnihexProvider.ReaderOutput output) throws IOException {
int line = 0;
ByteList buffer = new ByteArrayList(128);
while (true) {
boolean foundColon = copyUntil(input, buffer, 58);
int codepointDigitCount = buffer.size();
if (codepointDigitCount == 0 && !foundColon) {
return;
}
if (!foundColon || codepointDigitCount != 4 && codepointDigitCount != 5 && codepointDigitCount != 6) {
throw new IllegalArgumentException("Invalid entry at line " + line + ": expected 4, 5 or 6 hex digits followed by a colon");
}
int codepoint = 0;
for (int i = 0; i < codepointDigitCount; i++) {
codepoint = codepoint << 4 | decodeHex(line, buffer.getByte(i));
}
buffer.clear();
copyUntil(input, buffer, 10);
int dataDigitCount = buffer.size();
UnihexProvider.LineData contents = switch (dataDigitCount) {
case 32 -> UnihexProvider.ByteContents.read(line, buffer);
case 64 -> UnihexProvider.ShortContents.read(line, buffer);
case 96 -> UnihexProvider.IntContents.read24(line, buffer);
case 128 -> UnihexProvider.IntContents.read32(line, buffer);
default -> throw new IllegalArgumentException(
"Invalid entry at line " + line + ": expected hex number describing (8,16,24,32) x 16 bitmap, followed by a new line"
);
};
output.accept(codepoint, contents);
line++;
buffer.clear();
}
}
private static int decodeHex(int line, ByteList input, int index) {
return decodeHex(line, input.getByte(index));
}
private static int decodeHex(int line, byte b) {
return switch (b) {
case 48 -> 0;
case 49 -> 1;
case 50 -> 2;
case 51 -> 3;
case 52 -> 4;
case 53 -> 5;
case 54 -> 6;
case 55 -> 7;
case 56 -> 8;
case 57 -> 9;
default -> throw new IllegalArgumentException("Invalid entry at line " + line + ": expected hex digit, got " + (char)b);
case 65 -> 10;
case 66 -> 11;
case 67 -> 12;
case 68 -> 13;
case 69 -> 14;
case 70 -> 15;
};
}
private static boolean copyUntil(InputStream input, ByteList output, int delimiter) throws IOException {
while (true) {
int b = input.read();
if (b == -1) {
return false;
}
if (b == delimiter) {
return true;
}
output.add((byte)b);
}
}
@OnlyIn(Dist.CLIENT)
private record ByteContents(byte[] contents) implements UnihexProvider.LineData {
@Override
public int line(int index) {
return this.contents[index] << 24;
}
private static UnihexProvider.LineData read(int line, ByteList input) {
byte[] content = new byte[16];
int pos = 0;
for (int i = 0; i < 16; i++) {
int n1 = UnihexProvider.decodeHex(line, input, pos++);
int n0 = UnihexProvider.decodeHex(line, input, pos++);
byte v = (byte)(n1 << 4 | n0);
content[i] = v;
}
return new UnihexProvider.ByteContents(content);
}
@Override
public int bitWidth() {
return 8;
}
}
@OnlyIn(Dist.CLIENT)
public static class Definition implements GlyphProviderDefinition {
public static final MapCodec<UnihexProvider.Definition> CODEC = RecordCodecBuilder.mapCodec(
i -> i.group(
Identifier.CODEC.fieldOf("hex_file").forGetter(o -> o.hexFile),
UnihexProvider.OverrideRange.CODEC.listOf().optionalFieldOf("size_overrides", List.of()).forGetter(o -> o.sizeOverrides)
)
.apply(i, UnihexProvider.Definition::new)
);
private final Identifier hexFile;
private final List<UnihexProvider.OverrideRange> sizeOverrides;
private Definition(Identifier hexFile, List<UnihexProvider.OverrideRange> sizeOverrides) {
this.hexFile = hexFile;
this.sizeOverrides = sizeOverrides;
}
@Override
public GlyphProviderType type() {
return GlyphProviderType.UNIHEX;
}
@Override
public Either<GlyphProviderDefinition.Loader, GlyphProviderDefinition.Reference> unpack() {
return Either.left(this::load);
}
private GlyphProvider load(ResourceManager resourceManager) throws IOException {
UnihexProvider var3;
try (InputStream raw = resourceManager.open(this.hexFile)) {
var3 = this.loadData(raw);
}
return var3;
}
private UnihexProvider loadData(InputStream zipFile) throws IOException {
CodepointMap<UnihexProvider.LineData> bits = new CodepointMap<>(UnihexProvider.LineData[]::new, UnihexProvider.LineData[][]::new);
UnihexProvider.ReaderOutput output = bits::put;
UnihexProvider var17;
try (ZipInputStream zis = new ZipInputStream(zipFile)) {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
String name = entry.getName();
if (name.endsWith(".hex")) {
UnihexProvider.LOGGER.info("Found {}, loading", name);
UnihexProvider.readFromStream(new FastBufferedInputStream(zis), output);
}
}
CodepointMap<UnihexProvider.Glyph> glyphs = new CodepointMap<>(UnihexProvider.Glyph[]::new, UnihexProvider.Glyph[][]::new);
for (UnihexProvider.OverrideRange sizeOverride : this.sizeOverrides) {
int from = sizeOverride.from;
int to = sizeOverride.to;
UnihexProvider.Dimensions size = sizeOverride.dimensions;
for (int c = from; c <= to; c++) {
UnihexProvider.LineData codepointBits = bits.remove(c);
if (codepointBits != null) {
glyphs.put(c, new UnihexProvider.Glyph(codepointBits, size.left, size.right));
}
}
}
bits.forEach((codepoint, glyphBits) -> {
int packedSize = glyphBits.calculateWidth();
int left = UnihexProvider.Dimensions.left(packedSize);
int right = UnihexProvider.Dimensions.right(packedSize);
glyphs.put(codepoint, new UnihexProvider.Glyph(glyphBits, left, right));
});
var17 = new UnihexProvider(glyphs);
}
return var17;
}
}
@OnlyIn(Dist.CLIENT)
public record Dimensions(int left, int right) {
public static final MapCodec<UnihexProvider.Dimensions> MAP_CODEC = RecordCodecBuilder.mapCodec(
i -> i.group(
Codec.INT.fieldOf("left").forGetter(UnihexProvider.Dimensions::left),
Codec.INT.fieldOf("right").forGetter(UnihexProvider.Dimensions::right)
)
.apply(i, UnihexProvider.Dimensions::new)
);
public static final Codec<UnihexProvider.Dimensions> CODEC = MAP_CODEC.codec();
public int pack() {
return pack(this.left, this.right);
}
public static int pack(int left, int right) {
return (left & 0xFF) << 8 | right & 0xFF;
}
public static int left(int packed) {
return (byte)(packed >> 8);
}
public static int right(int packed) {
return (byte)packed;
}
}
@OnlyIn(Dist.CLIENT)
private record Glyph(UnihexProvider.LineData contents, int left, int right) implements UnbakedGlyph {
public int width() {
return this.right - this.left + 1;
}
@Override
public GlyphInfo info() {
return new GlyphInfo() {
{
Objects.requireNonNull(Glyph.this);
}
@Override
public float getAdvance() {
return Glyph.this.width() / 2 + 1;
}
@Override
public float getShadowOffset() {
return 0.5F;
}
@Override
public float getBoldOffset() {
return 0.5F;
}
};
}
@Override
public BakedGlyph bake(UnbakedGlyph.Stitcher stitcher) {
return stitcher.stitch(
this.info(),
new GlyphBitmap() {
{
Objects.requireNonNull(Glyph.this);
}
@Override
public float getOversample() {
return 2.0F;
}
@Override
public int getPixelWidth() {
return Glyph.this.width();
}
@Override
public int getPixelHeight() {
return 16;
}
@Override
public void upload(int x, int y, GpuTexture texture) {
IntBuffer targetBuffer = MemoryUtil.memAllocInt(Glyph.this.width() * 16);
UnihexProvider.unpackBitsToBytes(targetBuffer, Glyph.this.contents, Glyph.this.left, Glyph.this.right);
targetBuffer.rewind();
RenderSystem.getDevice()
.createCommandEncoder()
.writeToTexture(texture, MemoryUtil.memByteBuffer(targetBuffer), NativeImage.Format.RGBA, 0, 0, x, y, Glyph.this.width(), 16);
MemoryUtil.memFree(targetBuffer);
}
@Override
public boolean isColored() {
return true;
}
}
);
}
}
@OnlyIn(Dist.CLIENT)
private record IntContents(int[] contents, int bitWidth) implements UnihexProvider.LineData {
private static final int SIZE_24 = 24;
@Override
public int line(int index) {
return this.contents[index];
}
private static UnihexProvider.LineData read24(int line, ByteList input) {
int[] content = new int[16];
int mask = 0;
int pos = 0;
for (int i = 0; i < 16; i++) {
int n5 = UnihexProvider.decodeHex(line, input, pos++);
int n4 = UnihexProvider.decodeHex(line, input, pos++);
int n3 = UnihexProvider.decodeHex(line, input, pos++);
int n2 = UnihexProvider.decodeHex(line, input, pos++);
int n1 = UnihexProvider.decodeHex(line, input, pos++);
int n0 = UnihexProvider.decodeHex(line, input, pos++);
int v = n5 << 20 | n4 << 16 | n3 << 12 | n2 << 8 | n1 << 4 | n0;
content[i] = v << 8;
mask |= v;
}
return new UnihexProvider.IntContents(content, 24);
}
public static UnihexProvider.LineData read32(int line, ByteList input) {
int[] content = new int[16];
int mask = 0;
int pos = 0;
for (int i = 0; i < 16; i++) {
int n7 = UnihexProvider.decodeHex(line, input, pos++);
int n6 = UnihexProvider.decodeHex(line, input, pos++);
int n5 = UnihexProvider.decodeHex(line, input, pos++);
int n4 = UnihexProvider.decodeHex(line, input, pos++);
int n3 = UnihexProvider.decodeHex(line, input, pos++);
int n2 = UnihexProvider.decodeHex(line, input, pos++);
int n1 = UnihexProvider.decodeHex(line, input, pos++);
int n0 = UnihexProvider.decodeHex(line, input, pos++);
int v = n7 << 28 | n6 << 24 | n5 << 20 | n4 << 16 | n3 << 12 | n2 << 8 | n1 << 4 | n0;
content[i] = v;
mask |= v;
}
return new UnihexProvider.IntContents(content, 32);
}
}
@OnlyIn(Dist.CLIENT)
public interface LineData {
int line(int index);
int bitWidth();
default int mask() {
int mask = 0;
for (int i = 0; i < 16; i++) {
mask |= this.line(i);
}
return mask;
}
default int calculateWidth() {
int mask = this.mask();
int bitWidth = this.bitWidth();
int left;
int right;
if (mask == 0) {
left = 0;
right = bitWidth;
} else {
left = Integer.numberOfLeadingZeros(mask);
right = 32 - Integer.numberOfTrailingZeros(mask) - 1;
}
return UnihexProvider.Dimensions.pack(left, right);
}
}
@OnlyIn(Dist.CLIENT)
private record OverrideRange(int from, int to, UnihexProvider.Dimensions dimensions) {
private static final Codec<UnihexProvider.OverrideRange> RAW_CODEC = RecordCodecBuilder.create(
i -> i.group(
ExtraCodecs.CODEPOINT.fieldOf("from").forGetter(UnihexProvider.OverrideRange::from),
ExtraCodecs.CODEPOINT.fieldOf("to").forGetter(UnihexProvider.OverrideRange::to),
UnihexProvider.Dimensions.MAP_CODEC.forGetter(UnihexProvider.OverrideRange::dimensions)
)
.apply(i, UnihexProvider.OverrideRange::new)
);
public static final Codec<UnihexProvider.OverrideRange> CODEC = RAW_CODEC.validate(
o -> o.from >= o.to ? DataResult.error(() -> "Invalid range: [" + o.from + ";" + o.to + "]") : DataResult.success(o)
);
}
@FunctionalInterface
@OnlyIn(Dist.CLIENT)
public interface ReaderOutput {
void accept(int codepoint, UnihexProvider.LineData glyph);
}
@OnlyIn(Dist.CLIENT)
private record ShortContents(short[] contents) implements UnihexProvider.LineData {
@Override
public int line(int index) {
return this.contents[index] << 16;
}
private static UnihexProvider.LineData read(int line, ByteList input) {
short[] content = new short[16];
int pos = 0;
for (int i = 0; i < 16; i++) {
int n3 = UnihexProvider.decodeHex(line, input, pos++);
int n2 = UnihexProvider.decodeHex(line, input, pos++);
int n1 = UnihexProvider.decodeHex(line, input, pos++);
int n0 = UnihexProvider.decodeHex(line, input, pos++);
short v = (short)(n3 << 12 | n2 << 8 | n1 << 4 | n0);
content[i] = v;
}
return new UnihexProvider.ShortContents(content);
}
@Override
public int bitWidth() {
return 16;
}
}
}引用的其他类
-
- 引用位置:
构造调用 - 关联成员:
GlyphBitmap()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
GlyphInfo()
- 引用位置:
-
- 引用位置:
实现
- 引用位置:
-
- 引用位置:
返回值
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
RenderSystem.getDevice()
- 引用位置:
-
- 引用位置:
参数/字段
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
FastBufferedInputStream()
- 引用位置: