Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
183 changes: 105 additions & 78 deletions src/main/java/betterquesting/api/utils/RenderUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import java.awt.Color;
import java.nio.FloatBuffer;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Stack;
Expand Down Expand Up @@ -42,6 +44,7 @@ public class RenderUtils {
public static final RenderItem itemRender = new RenderItem();

private static final int SPLIT_STRING_TRIAL_LIMIT = 1000;
private static final Stack<IGuiRect> scissorStack = new Stack<>();

public static void RenderItemStack(Minecraft mc, ItemStack stack, int x, int y, String text) {
RenderItemStack(mc, stack, x, y, 16F, text, 0xFFFFFFFF);
Expand Down Expand Up @@ -71,7 +74,7 @@ public static void RenderItemStack(Minecraft mc, ItemStack stack, int x, int y,

GL11.glTranslatef(0.0F, 0.0F, z);
itemRender.zLevel = -50F; // Counters internal Z depth change so that GL translation makes sense // NOTE:
// Slightly different depth in 1.7.10
// Slightly different depth in 1.7.10

FontRenderer font = stack.getItem()
.getFontRenderer(stack);
Expand Down Expand Up @@ -138,7 +141,7 @@ public static void RenderEntity(float posX, float posY, float posZ, int scale, f
GL11.glEnable(GL11.GL_DEPTH_TEST);
GL11.glTranslatef(posX, posY, posZ);
GL11.glScalef((float) -scale, (float) scale, (float) scale); // Not entirely sure why mobs are flipped but
// this is how vanilla GUIs fix it so...
// this is how vanilla GUIs fix it so...
GL11.glRotatef(180F, 0F, 0F, 1F);
GL11.glRotatef(pitch, 1F, 0F, 0F);
GL11.glRotatef(rotation, 0F, 1F, 0F);
Expand Down Expand Up @@ -244,13 +247,13 @@ public static void drawSplitString(FontRenderer renderer, String string, int x,
splitString(string, width, renderer).size() - 1);
}

// TODO: Clean this up. The list of parameters is getting a bit excessive

public static void drawSplitString(FontRenderer renderer, String string, int x, int y, int width, int color,
boolean shadow, int start, int end) {
drawHighlightedSplitString(renderer, string, x, y, width, color, shadow, start, end, 0, 0, 0);
}

// TODO: Clean this up. The list of parameters is getting a bit excessive

public static void drawHighlightedSplitString(FontRenderer renderer, String string, int x, int y, int width,
int color, boolean shadow, int highlightColor, int highlightStart, int highlightEnd) {
drawHighlightedSplitString(
Expand Down Expand Up @@ -278,7 +281,7 @@ public static void drawHighlightedSplitString(FontRenderer renderer, String stri

List<String> list = splitString(string, width, renderer);
List<String> noFormat = splitStringWithoutFormat(string, width, renderer); // Needed for accurate highlight
// index positions
// index positions

if (list.size() != noFormat.size()) {
// BetterQuesting.logger.error("Line count mismatch (" + list.size() + " != " + noFormat.size() + ") while
Expand Down Expand Up @@ -444,8 +447,6 @@ public static void drawColoredRect(IGuiRect rect, IGuiColor color) {
GL11.glDisable(GL11.GL_BLEND);
}

private static final Stack<IGuiRect> scissorStack = new Stack<>();

/**
* Performs a OpenGL scissor based on Minecraft's resolution instead of display resolution and adds it to the stack
* of ongoing scissors.
Expand Down Expand Up @@ -510,84 +511,105 @@ public static void endScissor() {
}
}

private static Locale getLocale() {
var lang = Minecraft.getMinecraft()
.getLanguageManager()
.getCurrentLanguage();

var locale = Locale.forLanguageTag(
lang.toString()
.replace(" (", "-")
.replace(")", ""));

if (locale.getCountry()
.isEmpty()) {
locale = Locale.forLanguageTag(lang.getLanguageCode());
}
if (locale.getCountry()
.isEmpty()) {
locale = Locale.ENGLISH;
}
return locale;
}

/**
* Similar to normally splitting a string with the fontRenderer however this variant does
* not attempt to preserve the formatting between lines. This is particularly important when the
* index positions in the text are required to match the original unwrapped text.
*
* @return The lines used for editing, with exact characters matching the original text on each index
*/
public static List<String> splitStringWithoutFormat(String str, int wrapWidth, FontRenderer font) {
List<String> list = new ArrayList<>();

String lastFormat = ""; // Formatting like bold can affect the wrapping width
String temp = str;

int trial = 0;

while (true) {
// in some cases this goes into infinite loop
// todo: figure out fundamental fix
trial++;
if (trial > SPLIT_STRING_TRIAL_LIMIT) break;
return splitString(str, wrapWidth, font, false);
}

int i = sizeStringToWidth(lastFormat + temp, wrapWidth, font); // Cut to size WITH formatting
i -= lastFormat.length(); // Remove formatting characters from count
/**
* @return The lines used for rendering, preserving formatting codes across lines
*/
public static List<String> splitString(String str, int wrapWidth, FontRenderer font) {
return splitString(str, wrapWidth, font, true);
}

if (temp.length() <= i) {
list.add(temp);
break;
} else {
String s = temp.substring(0, i);
char c0 = temp.charAt(i);
boolean flag = c0 == ' ' || c0 == '\n';
lastFormat = getFormatFromString(lastFormat + s);
temp = temp.substring(i + (flag ? 1 : 0));
// NOTE: The index actually stops just before the space/nl so we don't need to remove it from THIS line.
// This is why the previous line moves forward by one for the NEXT line
list.add(s + (flag ? "\n" : "")); // Although we need to remove the spaces between each line we have to
// replace them with invisible new line characters to preserve the
// index count

if (temp.length() <= 0 && !flag) {
break;
private static List<String> splitString(final String str, final int wrapWidth, final FontRenderer font,
final boolean withFormat) {
if (str == null || str.isEmpty()) return Collections.emptyList();

var lines = str.split("\n", -1);
var locale = getLocale();
final List<String> wraps = new ArrayList<>();
String format = "";

int l = 1;
for (var line : lines) {
final BreakIterator breaker = BreakIterator.getLineInstance(locale);
breaker.setText(line);

int start = breaker.first();
int width = 0;
StringBuilder buf = new StringBuilder(format);

for (int end = breaker.next(); end != BreakIterator.DONE;) {
String candidate = line.substring(start, end);
String stripped = stripTrailing(candidate);
int needWidth = getStringWidth(stripped, font);
int realWidth = getStringWidth(candidate, font);

if (width + needWidth < wrapWidth) {
buf.append(candidate);
width += realWidth;
format = withFormat ? getFormatFromString(format + candidate) : "";
start = end;
end = breaker.next();
} else if (needWidth > wrapWidth) {
int i = sizeStringToWidth(candidate, wrapWidth, font);
buf.append(candidate, 0, i);
wraps.add(buf.toString());
buf = new StringBuilder(format);
width = 0;
start += i;
} else {
wraps.add(buf.toString());
buf = new StringBuilder(format);
width = 0;
}
}

// add back newlines eaten in order to keep exact the same text length when !withFormat, used for text
// editing calculations
if (!withFormat && l++ != lines.length) buf.append('\n');
// noinspection SizeReplaceableByIsEmpty
wraps.add(buf.length() == 0 ? format : buf.toString());
}
return wraps;

return list;
}

public static List<String> splitString(String str, int wrapWidth, FontRenderer font) {
List<String> list = new ArrayList<>();

String temp = str;

int trial = 0;

while (true) {
// in some cases this goes into infinite loop
// todo: figure out fundamental fix
trial++;
if (trial > SPLIT_STRING_TRIAL_LIMIT) break;

int i = sizeStringToWidth(temp, wrapWidth, font); // Cut to size WITH formatting

if (temp.length() <= i) {
list.add(temp);
break;
} else {
String s = temp.substring(0, i);
char c0 = temp.charAt(i);
boolean flag = c0 == ' ' || c0 == '\n';
temp = getFormatFromString(s) + temp.substring(i + (flag ? 1 : 0));
list.add(s);

if (temp.length() <= 0 && !flag) {
break;
}
}
private static String stripTrailing(String value) {
int length = value.length();
while (length > 0 && Character.isWhitespace(value.charAt(length - 1))) {
length--;
}

return list;
return value.substring(0, length);
}

/**
Expand Down Expand Up @@ -637,8 +659,9 @@ public static int getCursorPos(String text, int x, int y, int width, FontRendere
return idx + getCursorPos(lastFormat + tLines.get(row), x, font) - lastFormat.length();
}

// extract the format codes from one line to be applied to the following lines
public static String getFormatFromString(String p_78282_0_) {
String s1 = "";
StringBuilder s1 = new StringBuilder();
int i = -1;
int j = p_78282_0_.length();

Expand All @@ -647,14 +670,18 @@ public static String getFormatFromString(String p_78282_0_) {
char c0 = p_78282_0_.charAt(i + 1);

if (isFormatColor(c0)) {
s1 = "\u00a7" + c0;
s1 = new StringBuilder("§" + c0);
} else if (isFormatSpecial(c0)) {
s1 = s1 + "\u00a7" + c0;
s1.append("§")
.append(c0);
}
}
}
if (s1.length() <= 0) return "";
// §r means reset, so whenever it appears at the end of a formatting, it implies do nothing.
if (s1.charAt(s1.length() - 1) == 'r') return "";

return s1;
return s1.toString();
}

private static int sizeStringToWidth(String str, int wrapWidth, FontRenderer font) {
Expand Down Expand Up @@ -972,11 +999,11 @@ public static void drawGradientRect(int zDepth, int p_drawGradientRect_1_, int p
Tessellator var15 = Tessellator.instance;
var15.startDrawingQuads();
var15.setColorRGBA_F(var8, var9, var10, var7);
var15.addVertex((double) p_drawGradientRect_3_, (double) p_drawGradientRect_2_, (double) zDepth);
var15.addVertex((double) p_drawGradientRect_1_, (double) p_drawGradientRect_2_, (double) zDepth);
var15.addVertex(p_drawGradientRect_3_, p_drawGradientRect_2_, zDepth);
var15.addVertex(p_drawGradientRect_1_, p_drawGradientRect_2_, zDepth);
var15.setColorRGBA_F(var12, var13, var14, var11);
var15.addVertex((double) p_drawGradientRect_1_, (double) p_drawGradientRect_4_, (double) zDepth);
var15.addVertex((double) p_drawGradientRect_3_, (double) p_drawGradientRect_4_, (double) zDepth);
var15.addVertex(p_drawGradientRect_1_, p_drawGradientRect_4_, zDepth);
var15.addVertex(p_drawGradientRect_3_, p_drawGradientRect_4_, zDepth);
var15.draw();
GL11.glShadeModel(7424);
GL11.glDisable(3042);
Expand Down