127 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			127 lines
		
	
	
	
		
			3.9 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.GpuDevice;
 | |
| 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);
 | |
| 		GpuDevice gpuDevice = RenderSystem.getDevice();
 | |
| 		this.texture = gpuDevice.createTexture(label, 7, colored ? TextureFormat.RGBA8 : TextureFormat.RED8, 256, 256, 1, 1);
 | |
| 		this.texture.setTextureFilter(FilterMode.NEAREST, false);
 | |
| 		this.textureView = gpuDevice.createTextureView(this.texture);
 | |
| 		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 && this.textureView != 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,
 | |
| 					this.textureView,
 | |
| 					(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);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 |