From 180aad05decc7eefa87e4e45d6747c48f40e5361 Mon Sep 17 00:00:00 2001 From: Tyler Murphy Date: Mon, 17 Apr 2023 12:12:01 -0400 Subject: save --- .../tylermurphy/Minecraft/UI/Text/Character.java | 72 ++++++++++ .../net/tylermurphy/Minecraft/UI/Text/Line.java | 44 ++++++ .../tylermurphy/Minecraft/UI/Text/MetaFile.java | 157 +++++++++++++++++++++ .../tylermurphy/Minecraft/UI/Text/TextMaster.java | 63 +++++++++ .../Minecraft/UI/Text/TextMeshCreator.java | 140 ++++++++++++++++++ .../Minecraft/UI/Text/TextMeshData.java | 25 ++++ .../net/tylermurphy/Minecraft/UI/Text/Word.java | 29 ++++ 7 files changed, 530 insertions(+) create mode 100755 src/main/java/net/tylermurphy/Minecraft/UI/Text/Character.java create mode 100755 src/main/java/net/tylermurphy/Minecraft/UI/Text/Line.java create mode 100755 src/main/java/net/tylermurphy/Minecraft/UI/Text/MetaFile.java create mode 100755 src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMaster.java create mode 100755 src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshCreator.java create mode 100755 src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshData.java create mode 100755 src/main/java/net/tylermurphy/Minecraft/UI/Text/Word.java (limited to 'src/main/java/net/tylermurphy/Minecraft/UI/Text') diff --git a/src/main/java/net/tylermurphy/Minecraft/UI/Text/Character.java b/src/main/java/net/tylermurphy/Minecraft/UI/Text/Character.java new file mode 100755 index 0000000..d7d78cf --- /dev/null +++ b/src/main/java/net/tylermurphy/Minecraft/UI/Text/Character.java @@ -0,0 +1,72 @@ +package net.tylermurphy.Minecraft.UI.Text; + + +public class Character { + + private int id; + private double xTextureCoord; + private double yTextureCoord; + private double xMaxTextureCoord; + private double yMaxTextureCoord; + private double xOffset; + private double yOffset; + private double sizeX; + private double sizeY; + private double xAdvance; + + + protected Character(int id, double xTextureCoord, double yTextureCoord, double xTexSize, double yTexSize, + double xOffset, double yOffset, double sizeX, double sizeY, double xAdvance) { + this.id = id; + this.xTextureCoord = xTextureCoord; + this.yTextureCoord = yTextureCoord; + this.xOffset = xOffset; + this.yOffset = yOffset; + this.sizeX = sizeX; + this.sizeY = sizeY; + this.xMaxTextureCoord = xTexSize + xTextureCoord; + this.yMaxTextureCoord = yTexSize + yTextureCoord; + this.xAdvance = xAdvance; + } + + protected int getId() { + return id; + } + + protected double getxTextureCoord() { + return xTextureCoord; + } + + protected double getyTextureCoord() { + return yTextureCoord; + } + + protected double getXMaxTextureCoord() { + return xMaxTextureCoord; + } + + protected double getYMaxTextureCoord() { + return yMaxTextureCoord; + } + + protected double getxOffset() { + return xOffset; + } + + protected double getyOffset() { + return yOffset; + } + + protected double getSizeX() { + return sizeX; + } + + protected double getSizeY() { + return sizeY; + } + + protected double getxAdvance() { + return xAdvance; + } + +} diff --git a/src/main/java/net/tylermurphy/Minecraft/UI/Text/Line.java b/src/main/java/net/tylermurphy/Minecraft/UI/Text/Line.java new file mode 100755 index 0000000..ec80db5 --- /dev/null +++ b/src/main/java/net/tylermurphy/Minecraft/UI/Text/Line.java @@ -0,0 +1,44 @@ +package net.tylermurphy.Minecraft.UI.Text; + +import java.util.ArrayList; +import java.util.List; + +public class Line { + + private double maxLength; + private double spaceSize; + + private List words = new ArrayList(); + private double currentLineLength = 0; + + + protected Line(double spaceWidth, double fontSize, double maxLength) { + this.spaceSize = spaceWidth * fontSize; + this.maxLength = maxLength; + } + + protected boolean attemptToAddWord(Word word) { + double additionalLength = word.getWordWidth(); + additionalLength += !words.isEmpty() ? spaceSize : 0; + if (currentLineLength + additionalLength <= maxLength) { + words.add(word); + currentLineLength += additionalLength; + return true; + } else { + return false; + } + } + + protected double getMaxLength() { + return maxLength; + } + + protected double getLineLength() { + return currentLineLength; + } + + protected List getWords() { + return words; + } + +} diff --git a/src/main/java/net/tylermurphy/Minecraft/UI/Text/MetaFile.java b/src/main/java/net/tylermurphy/Minecraft/UI/Text/MetaFile.java new file mode 100755 index 0000000..1d22499 --- /dev/null +++ b/src/main/java/net/tylermurphy/Minecraft/UI/Text/MetaFile.java @@ -0,0 +1,157 @@ +package net.tylermurphy.Minecraft.UI.Text; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import net.tylermurphy.Minecraft.Util.Constants; +import net.tylermurphy.Minecraft.Render.Data.Display; + +public class MetaFile { + + private static final int PAD_TOP = 0; + private static final int PAD_LEFT = 1; + private static final int PAD_BOTTOM = 2; + private static final int PAD_RIGHT = 3; + + private static final int DESIRED_PADDING = 8; + + private static final String SPLITTER = " "; + private static final String NUMBER_SEPARATOR = ","; + + private double aspectRatio; + + private double verticalPerPixelSize; + private double horizontalPerPixelSize; + private double spaceWidth; + private int[] padding; + private int paddingWidth; + private int paddingHeight; + + private Map metaData = new HashMap(); + + private BufferedReader reader; + private Map values = new HashMap(); + + protected MetaFile(String file) { + this.aspectRatio = (double) Display.getWidth() / (double) Display.getHeight(); + openFile(file); + loadPaddingData(); + loadLineSizes(); + int imageWidth = getValueOfVariable("scaleW"); + loadCharacterData(imageWidth); + close(); + } + + protected double getSpaceWidth() { + return spaceWidth; + } + + protected Character getCharacter(int ascii) { + return metaData.get(ascii); + } + + private boolean processNextLine() { + values.clear(); + String line = null; + try { + line = reader.readLine(); + } catch (IOException e1) { + } + if (line == null) { + return false; + } + for (String part : line.split(SPLITTER)) { + String[] valuePairs = part.split("="); + if (valuePairs.length == 2) { + values.put(valuePairs[0], valuePairs[1]); + } + } + return true; + } + + private int getValueOfVariable(String variable) { + int i = 0; + try { + i = Integer.parseInt(values.get(variable)); + }catch(Exception e) { + e.printStackTrace(); + } + return i; + } + + private int[] getValuesOfVariable(String variable) { + String[] numbers = values.get(variable).split(NUMBER_SEPARATOR); + int[] actualValues = new int[numbers.length]; + for (int i = 0; i < actualValues.length; i++) { + actualValues[i] = Integer.parseInt(numbers[i]); + } + return actualValues; + } + + private void close() { + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private void openFile(String file) { + try { + FileReader isr = new FileReader(new File(Constants.FNT_LOCATION + file + ".fnt")); + reader = new BufferedReader(isr); + } catch (Exception e) { + e.printStackTrace(); + System.err.println("Couldn't read font meta file!"); + } + } + + private void loadPaddingData() { + processNextLine(); + this.padding = getValuesOfVariable("padding"); + this.paddingWidth = padding[PAD_LEFT] + padding[PAD_RIGHT]; + this.paddingHeight = padding[PAD_TOP] + padding[PAD_BOTTOM]; + } + + private void loadLineSizes() { + processNextLine(); + int lineHeightPixels = getValueOfVariable("lineHeight") - paddingHeight; + verticalPerPixelSize = TextMeshCreator.LINE_HEIGHT / (double) lineHeightPixels; + horizontalPerPixelSize = verticalPerPixelSize / aspectRatio; + } + + private void loadCharacterData(int imageWidth) { + processNextLine(); + processNextLine(); + while (processNextLine()) { + Character c = loadCharacter(imageWidth); + if (c != null) { + metaData.put(c.getId(), c); + } + } + } + + private Character loadCharacter(int imageSize) { + int id = getValueOfVariable("id"); + if (id == TextMeshCreator.SPACE_ASCII) { + this.spaceWidth = (getValueOfVariable("xadvance") - paddingWidth) * horizontalPerPixelSize; + return null; + } + double xTex = ((double) getValueOfVariable("x") + (padding[PAD_LEFT] - DESIRED_PADDING)) / imageSize; + double yTex = ((double) getValueOfVariable("y") + (padding[PAD_TOP] - DESIRED_PADDING)) / imageSize; + int width = getValueOfVariable("width") - (paddingWidth - (2 * DESIRED_PADDING)); + int height = getValueOfVariable("height") - ((paddingHeight) - (2 * DESIRED_PADDING)); + double quadWidth = width * horizontalPerPixelSize; + double quadHeight = height * verticalPerPixelSize; + double xTexSize = (double) width / imageSize; + double yTexSize = (double) height / imageSize; + double xOff = (getValueOfVariable("xoffset") + padding[PAD_LEFT] - DESIRED_PADDING) * horizontalPerPixelSize; + double yOff = (getValueOfVariable("yoffset") + (padding[PAD_TOP] - DESIRED_PADDING)) * verticalPerPixelSize; + double xAdvance = (getValueOfVariable("xadvance") - paddingWidth) * horizontalPerPixelSize; + return new Character(id, xTex, yTex, xTexSize, yTexSize, xOff, yOff, quadWidth, quadHeight, xAdvance); + } +} diff --git a/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMaster.java b/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMaster.java new file mode 100755 index 0000000..2616722 --- /dev/null +++ b/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMaster.java @@ -0,0 +1,63 @@ +package net.tylermurphy.Minecraft.UI.Text; + +import java.util.ArrayList; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.tylermurphy.Minecraft.Render.FontRenderer; +import net.tylermurphy.Minecraft.UI.UIComponent; +import net.tylermurphy.Minecraft.UI.UIFont; +import net.tylermurphy.Minecraft.UI.UIText; + +public class TextMaster { + + private static Map> texts = new HashMap>(); + + private static void proccessText(UIText text) { + UIFont fontType = text.getFont(); + List batch = texts.get(fontType); + if (batch != null) { + batch.add(text); + } else { + List newBatch = new ArrayList(); + newBatch.add(text); + texts.put(fontType, newBatch); + } + } + + public static void render(List components,FontRenderer fontrenderer){ + for(UIComponent component : components) { + UIText text; + if(component instanceof UIText) { + text = (UIText)component; + } else { + continue; + } + loadText(text); + proccessText(text); + } + fontrenderer.render(TextMaster.texts); + TextMaster.texts.clear(); + } + + public static void loadText(UIText text){ + UIFont font = text.getFont(); + List textBatch = texts.get(font); + if(textBatch == null){ + textBatch = new ArrayList(); + texts.put(font, textBatch); + } + textBatch.add(text); + } + + public static void removeText(UIText text){ + List textBatch = texts.get(text.getFont()); + textBatch.remove(text); + if(textBatch.isEmpty()){ + texts.remove(text.getFont()); + } + } + +} diff --git a/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshCreator.java b/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshCreator.java new file mode 100755 index 0000000..bd84abb --- /dev/null +++ b/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshCreator.java @@ -0,0 +1,140 @@ +package net.tylermurphy.Minecraft.UI.Text; + +import java.util.ArrayList; +import java.util.List; + +import net.tylermurphy.Minecraft.UI.UIText; + +public class TextMeshCreator { + + protected static final double LINE_HEIGHT = 0.03f; + protected static final int SPACE_ASCII = 32; + + private MetaFile metaData; + + public TextMeshCreator(String metaFile) { + metaData = new MetaFile(metaFile); + } + + public TextMeshData createTextMesh(UIText text) { + List lines = createStructure(text); + TextMeshData data = createQuadVertices(text, lines); + return data; + } + + private List createStructure(UIText text) { + char[] chars = text.getTextString().toCharArray(); + List lines = new ArrayList(); + Line currentLine = new Line(metaData.getSpaceWidth(), text.getFontSize(), text.getMaxLineSize()); + Word currentWord = new Word(text.getFontSize()); + for (char c : chars) { + int ascii = (int) c; + if (ascii == SPACE_ASCII) { + boolean added = currentLine.attemptToAddWord(currentWord); + if (!added) { + lines.add(currentLine); + currentLine = new Line(metaData.getSpaceWidth(), text.getFontSize(), text.getMaxLineSize()); + currentLine.attemptToAddWord(currentWord); + } + currentWord = new Word(text.getFontSize()); + continue; + } + Character character = metaData.getCharacter(ascii); + currentWord.addCharacter(character); + } + completeStructure(lines, currentLine, currentWord, text); + return lines; + } + + private void completeStructure(List lines, Line currentLine, Word currentWord, UIText text) { + boolean added = currentLine.attemptToAddWord(currentWord); + if (!added) { + lines.add(currentLine); + currentLine = new Line(metaData.getSpaceWidth(), text.getFontSize(), text.getMaxLineSize()); + currentLine.attemptToAddWord(currentWord); + } + lines.add(currentLine); + } + + private TextMeshData createQuadVertices(UIText text, List lines) { + text.setNumberOfLines(lines.size()); + double curserX = 0f; + double curserY = 0f; + double maxX = 0; + List vertices = new ArrayList(); + List textureCoords = new ArrayList(); + for (Line line : lines) { + if (text.isCentered()) { + curserX = (line.getMaxLength() - line.getLineLength()) / 2; + } + for (Word word : line.getWords()) { + for (Character letter : word.getCharacters()) { + double newMaxX = addVerticesForCharacter(curserX, curserY, letter, text.getFontSize(), vertices); + maxX = Math.max(newMaxX, maxX); + addTexCoords(textureCoords, letter.getxTextureCoord(), letter.getyTextureCoord(), + letter.getXMaxTextureCoord(), letter.getYMaxTextureCoord()); + curserX += letter.getxAdvance() * text.getFontSize(); + } + curserX += metaData.getSpaceWidth() * text.getFontSize(); + } + curserX = 0; + curserY += LINE_HEIGHT * text.getFontSize(); + } + text.setMaxX(maxX); + return new TextMeshData(listToArray(vertices), listToArray(textureCoords)); + } + + private double addVerticesForCharacter(double curserX, double curserY, Character character, double fontSize, + List vertices) { + double x = curserX + (character.getxOffset() * fontSize); + double y = curserY + (character.getyOffset() * fontSize); + double maxX = x + (character.getSizeX() * fontSize); + double maxY = y + (character.getSizeY() * fontSize); + double properX = (2 * x) - 1; + double properY = (-2 * y) + 1; + double properMaxX = (2 * maxX) - 1; + double properMaxY = (-2 * maxY) + 1; + addVertices(vertices, properX, properY, properMaxX, properMaxY); + return maxX; + } + + private static void addVertices(List vertices, double x, double y, double maxX, double maxY) { + vertices.add((float) x); + vertices.add((float) y); + vertices.add((float) x); + vertices.add((float) maxY); + vertices.add((float) maxX); + vertices.add((float) maxY); + vertices.add((float) maxX); + vertices.add((float) maxY); + vertices.add((float) maxX); + vertices.add((float) y); + vertices.add((float) x); + vertices.add((float) y); + } + + private static void addTexCoords(List texCoords, double x, double y, double maxX, double maxY) { + texCoords.add((float) x); + texCoords.add((float) y); + texCoords.add((float) x); + texCoords.add((float) maxY); + texCoords.add((float) maxX); + texCoords.add((float) maxY); + texCoords.add((float) maxX); + texCoords.add((float) maxY); + texCoords.add((float) maxX); + texCoords.add((float) y); + texCoords.add((float) x); + texCoords.add((float) y); + } + + + private static float[] listToArray(List listOfFloats) { + float[] array = new float[listOfFloats.size()]; + for (int i = 0; i < array.length; i++) { + array[i] = listOfFloats.get(i); + } + return array; + } + +} diff --git a/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshData.java b/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshData.java new file mode 100755 index 0000000..2226e93 --- /dev/null +++ b/src/main/java/net/tylermurphy/Minecraft/UI/Text/TextMeshData.java @@ -0,0 +1,25 @@ +package net.tylermurphy.Minecraft.UI.Text; + +public class TextMeshData { + + private float[] vertexPositions; + private float[] textureCoords; + + protected TextMeshData(float[] vertexPositions, float[] textureCoords){ + this.vertexPositions = vertexPositions; + this.textureCoords = textureCoords; + } + + public float[] getVertexPositions() { + return vertexPositions; + } + + public float[] getTextureCoords() { + return textureCoords; + } + + public int getVertexCount() { + return vertexPositions.length/2; + } + +} diff --git a/src/main/java/net/tylermurphy/Minecraft/UI/Text/Word.java b/src/main/java/net/tylermurphy/Minecraft/UI/Text/Word.java new file mode 100755 index 0000000..9256619 --- /dev/null +++ b/src/main/java/net/tylermurphy/Minecraft/UI/Text/Word.java @@ -0,0 +1,29 @@ +package net.tylermurphy.Minecraft.UI.Text; + +import java.util.ArrayList; +import java.util.List; + +public class Word { + + private List characters = new ArrayList(); + private double width = 0; + private double fontSize; + + protected Word(double fontSize){ + this.fontSize = fontSize; + } + + protected void addCharacter(Character character){ + characters.add(character); + width += character.getxAdvance() * fontSize; + } + + protected List getCharacters(){ + return characters; + } + + protected double getWordWidth(){ + return width; + } + +} -- cgit v1.2.3-freya