Spaces:
Build error
Build error
File size: 8,117 Bytes
d46f4a3 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
package net.minecraft.client.gui.font;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.blaze3d.font.GlyphInfo;
import com.mojang.blaze3d.font.GlyphProvider;
import com.mojang.blaze3d.font.SheetGlyphInfo;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
import it.unimi.dsi.fastutil.ints.IntSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.IntFunction;
import net.minecraft.client.gui.font.glyphs.BakedGlyph;
import net.minecraft.client.gui.font.glyphs.SpecialGlyphs;
import net.minecraft.client.renderer.texture.TextureManager;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.slf4j.Logger;
@OnlyIn(Dist.CLIENT)
public class FontSet implements AutoCloseable {
private static final Logger LOGGER = LogUtils.getLogger();
private static final RandomSource RANDOM = RandomSource.create();
private static final float LARGE_FORWARD_ADVANCE = 32.0F;
private final TextureManager textureManager;
private final ResourceLocation name;
private BakedGlyph missingGlyph;
private BakedGlyph whiteGlyph;
private List<GlyphProvider.Conditional> allProviders = List.of();
private List<GlyphProvider> activeProviders = List.of();
private final CodepointMap<BakedGlyph> glyphs = new CodepointMap<>(BakedGlyph[]::new, BakedGlyph[][]::new);
private final CodepointMap<FontSet.GlyphInfoFilter> glyphInfos = new CodepointMap<>(FontSet.GlyphInfoFilter[]::new, FontSet.GlyphInfoFilter[][]::new);
private final Int2ObjectMap<IntList> glyphsByWidth = new Int2ObjectOpenHashMap<>();
private final List<FontTexture> textures = Lists.newArrayList();
private final IntFunction<FontSet.GlyphInfoFilter> glyphInfoGetter = this::computeGlyphInfo;
private final IntFunction<BakedGlyph> glyphGetter = this::computeBakedGlyph;
public FontSet(TextureManager p_95062_, ResourceLocation p_95063_) {
this.textureManager = p_95062_;
this.name = p_95063_;
}
public void reload(List<GlyphProvider.Conditional> p_332248_, Set<FontOption> p_329677_) {
this.allProviders = p_332248_;
this.reload(p_329677_);
}
public void reload(Set<FontOption> p_331404_) {
this.activeProviders = List.of();
this.resetTextures();
this.activeProviders = this.selectProviders(this.allProviders, p_331404_);
}
private void resetTextures() {
this.closeTextures();
this.glyphs.clear();
this.glyphInfos.clear();
this.glyphsByWidth.clear();
this.missingGlyph = SpecialGlyphs.MISSING.bake(this::stitch);
this.whiteGlyph = SpecialGlyphs.WHITE.bake(this::stitch);
}
private List<GlyphProvider> selectProviders(List<GlyphProvider.Conditional> p_328855_, Set<FontOption> p_331640_) {
IntSet intset = new IntOpenHashSet();
List<GlyphProvider> list = new ArrayList<>();
for (GlyphProvider.Conditional glyphprovider$conditional : p_328855_) {
if (glyphprovider$conditional.filter().apply(p_331640_)) {
list.add(glyphprovider$conditional.provider());
intset.addAll(glyphprovider$conditional.provider().getSupportedGlyphs());
}
}
Set<GlyphProvider> set = Sets.newHashSet();
intset.forEach((int p_232561_) -> {
for (GlyphProvider glyphprovider : list) {
GlyphInfo glyphinfo = glyphprovider.getGlyph(p_232561_);
if (glyphinfo != null) {
set.add(glyphprovider);
if (glyphinfo != SpecialGlyphs.MISSING) {
this.glyphsByWidth.computeIfAbsent(Mth.ceil(glyphinfo.getAdvance(false)), p_232567_ -> new IntArrayList()).add(p_232561_);
}
break;
}
}
});
return list.stream().filter(set::contains).toList();
}
@Override
public void close() {
this.closeTextures();
}
private void closeTextures() {
for (FontTexture fonttexture : this.textures) {
fonttexture.close();
}
this.textures.clear();
}
private static boolean hasFishyAdvance(GlyphInfo p_243323_) {
float f = p_243323_.getAdvance(false);
if (!(f < 0.0F) && !(f > 32.0F)) {
float f1 = p_243323_.getAdvance(true);
return f1 < 0.0F || f1 > 32.0F;
} else {
return true;
}
}
private FontSet.GlyphInfoFilter computeGlyphInfo(int p_243321_) {
GlyphInfo glyphinfo = null;
for (GlyphProvider glyphprovider : this.activeProviders) {
GlyphInfo glyphinfo1 = glyphprovider.getGlyph(p_243321_);
if (glyphinfo1 != null) {
if (glyphinfo == null) {
glyphinfo = glyphinfo1;
}
if (!hasFishyAdvance(glyphinfo1)) {
return new FontSet.GlyphInfoFilter(glyphinfo, glyphinfo1);
}
}
}
return glyphinfo != null ? new FontSet.GlyphInfoFilter(glyphinfo, SpecialGlyphs.MISSING) : FontSet.GlyphInfoFilter.MISSING;
}
public GlyphInfo getGlyphInfo(int p_243235_, boolean p_243251_) {
return this.glyphInfos.computeIfAbsent(p_243235_, this.glyphInfoGetter).select(p_243251_);
}
private BakedGlyph computeBakedGlyph(int p_232565_) {
for (GlyphProvider glyphprovider : this.activeProviders) {
GlyphInfo glyphinfo = glyphprovider.getGlyph(p_232565_);
if (glyphinfo != null) {
return glyphinfo.bake(this::stitch);
}
}
LOGGER.warn("Couldn't find glyph for character {} (\\u{})", Character.toString(p_232565_), String.format("%04x", p_232565_));
return this.missingGlyph;
}
public BakedGlyph getGlyph(int p_95079_) {
return this.glyphs.computeIfAbsent(p_95079_, this.glyphGetter);
}
private BakedGlyph stitch(SheetGlyphInfo p_232557_) {
for (FontTexture fonttexture : this.textures) {
BakedGlyph bakedglyph = fonttexture.add(p_232557_);
if (bakedglyph != null) {
return bakedglyph;
}
}
ResourceLocation resourcelocation = this.name.withSuffix("/" + this.textures.size());
boolean flag = p_232557_.isColored();
GlyphRenderTypes glyphrendertypes = flag ? GlyphRenderTypes.createForColorTexture(resourcelocation) : GlyphRenderTypes.createForIntensityTexture(resourcelocation);
FontTexture fonttexture1 = new FontTexture(glyphrendertypes, flag);
this.textures.add(fonttexture1);
this.textureManager.register(resourcelocation, fonttexture1);
BakedGlyph bakedglyph1 = fonttexture1.add(p_232557_);
return bakedglyph1 == null ? this.missingGlyph : bakedglyph1;
}
public BakedGlyph getRandomGlyph(GlyphInfo p_95068_) {
IntList intlist = this.glyphsByWidth.get(Mth.ceil(p_95068_.getAdvance(false)));
return intlist != null && !intlist.isEmpty() ? this.getGlyph(intlist.getInt(RANDOM.nextInt(intlist.size()))) : this.missingGlyph;
}
public ResourceLocation name() {
return this.name;
}
public BakedGlyph whiteGlyph() {
return this.whiteGlyph;
}
@OnlyIn(Dist.CLIENT)
static record GlyphInfoFilter(GlyphInfo glyphInfo, GlyphInfo glyphInfoNotFishy) {
static final FontSet.GlyphInfoFilter MISSING = new FontSet.GlyphInfoFilter(SpecialGlyphs.MISSING, SpecialGlyphs.MISSING);
GlyphInfo select(boolean p_243218_) {
return p_243218_ ? this.glyphInfoNotFishy : this.glyphInfo;
}
}
}
|