minecraft-src/net/minecraft/client/gui/font/FontTexture.java
2025-07-04 03:45:38 +03:00

123 lines
3.7 KiB
Java

package net.minecraft.client.gui.font;
import com.mojang.blaze3d.font.SheetGlyphInfo;
import com.mojang.blaze3d.platform.TextureUtil;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.FilterMode;
import com.mojang.blaze3d.textures.TextureFormat;
import java.nio.file.Path;
import java.util.function.Supplier;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.font.glyphs.BakedGlyph;
import net.minecraft.client.renderer.texture.AbstractTexture;
import net.minecraft.client.renderer.texture.Dumpable;
import net.minecraft.resources.ResourceLocation;
import org.jetbrains.annotations.Nullable;
@Environment(EnvType.CLIENT)
public class FontTexture extends AbstractTexture implements Dumpable {
private static final int SIZE = 256;
private final GlyphRenderTypes renderTypes;
private final boolean colored;
private final FontTexture.Node root;
public FontTexture(Supplier<String> label, GlyphRenderTypes renderTypes, boolean colored) {
this.colored = colored;
this.root = new FontTexture.Node(0, 0, 256, 256);
this.texture = RenderSystem.getDevice().createTexture(label, colored ? TextureFormat.RGBA8 : TextureFormat.RED8, 256, 256, 1);
this.texture.setTextureFilter(FilterMode.NEAREST, false);
this.renderTypes = renderTypes;
}
@Nullable
public BakedGlyph add(SheetGlyphInfo glyphInfo) {
if (glyphInfo.isColored() != this.colored) {
return null;
} else {
FontTexture.Node node = this.root.insert(glyphInfo);
if (node != null && this.texture != null) {
glyphInfo.upload(node.x, node.y, this.texture);
float f = 256.0F;
float g = 256.0F;
float h = 0.01F;
return new BakedGlyph(
this.renderTypes,
(node.x + 0.01F) / 256.0F,
(node.x - 0.01F + glyphInfo.getPixelWidth()) / 256.0F,
(node.y + 0.01F) / 256.0F,
(node.y - 0.01F + glyphInfo.getPixelHeight()) / 256.0F,
glyphInfo.getLeft(),
glyphInfo.getRight(),
glyphInfo.getTop(),
glyphInfo.getBottom()
);
} else {
return null;
}
}
}
@Override
public void dumpContents(ResourceLocation resourceLocation, Path path) {
if (this.texture != null) {
String string = resourceLocation.toDebugFileName();
TextureUtil.writeAsPNG(path, string, this.texture, 0, i -> (i & 0xFF000000) == 0 ? -16777216 : i);
}
}
@Environment(EnvType.CLIENT)
static class Node {
final int x;
final int y;
private final int width;
private final int height;
@Nullable
private FontTexture.Node left;
@Nullable
private FontTexture.Node right;
private boolean occupied;
Node(int x, int y, int width, int height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
@Nullable
FontTexture.Node insert(SheetGlyphInfo glyphInfo) {
if (this.left != null && this.right != null) {
FontTexture.Node node = this.left.insert(glyphInfo);
if (node == null) {
node = this.right.insert(glyphInfo);
}
return node;
} else if (this.occupied) {
return null;
} else {
int i = glyphInfo.getPixelWidth();
int j = glyphInfo.getPixelHeight();
if (i > this.width || j > this.height) {
return null;
} else if (i == this.width && j == this.height) {
this.occupied = true;
return this;
} else {
int k = this.width - i;
int l = this.height - j;
if (k > l) {
this.left = new FontTexture.Node(this.x, this.y, i, this.height);
this.right = new FontTexture.Node(this.x + i + 1, this.y, this.width - i - 1, this.height);
} else {
this.left = new FontTexture.Node(this.x, this.y, this.width, j);
this.right = new FontTexture.Node(this.x, this.y + j + 1, this.width, this.height - j - 1);
}
return this.left.insert(glyphInfo);
}
}
}
}
}