Skip to content

Commit

Permalink
Batch string rendering for the HUDs, and fix MekaSuit hud not using w…
Browse files Browse the repository at this point in the history
…arning and danger colors for icons
  • Loading branch information
pupnewfster committed Aug 26, 2024
1 parent bfeebf8 commit c364e7f
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 44 deletions.
26 changes: 15 additions & 11 deletions src/main/java/mekanism/client/gui/GuiRadialSelector.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,18 +176,22 @@ record PositionedText(float x, float y, Component text) {}
textToDraw.add(new PositionedText(x, y, mode.sliceName()));
}

// Labels (has to be separate from icons or the icons occasionally will get extra artifacts for some reason)
boolean whiteRadialText = MekanismConfig.client.whiteRadialText.get();
for (PositionedText toDraw : textToDraw) {
pose.pushPose();
pose.translate(toDraw.x, toDraw.y, 0);
pose.scale(0.6F, 0.6F, 0.6F);
Component text = toDraw.text;
if (whiteRadialText) {
text = text.copy().withStyle(ChatFormatting.RESET);
if (!textToDraw.isEmpty()) {
// Labels (has to be separate from icons or the icons occasionally will get extra artifacts for some reason and also then we can't batch them)
boolean whiteRadialText = MekanismConfig.client.whiteRadialText.get();
for (PositionedText toDraw : textToDraw) {
pose.pushPose();
pose.translate(toDraw.x, toDraw.y, 0);
pose.scale(0.6F, 0.6F, 0.6F);
Component text = toDraw.text;
if (whiteRadialText) {
text = text.copy().withStyle(ChatFormatting.RESET);
}
GuiUtils.drawStringNoFlush(guiGraphics, font, text, -font.width(text) / 2F, 8, 0xCCFFFFFF, true);
pose.popPose();
}
GuiUtils.drawString(guiGraphics, font, text, -font.width(text) / 2F, 8, 0xCCFFFFFF, true);
pose.popPose();
//Flush and actually render out the labels
guiGraphics.flush();
}

pose.popPose();
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/mekanism/client/gui/GuiUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.events.GuiEventListener;
import net.minecraft.client.renderer.GameRenderer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.network.chat.Component;
Expand Down Expand Up @@ -254,6 +255,16 @@ public static int drawString(GuiGraphics guiGraphics, Font font, Component compo
return guiGraphics.drawString(font, component.getVisualOrderText(), x, y, color, drawShadow);
}

public static int drawStringNoFlush(GuiGraphics graphics, Font font, Component component, float x, float y, int color, boolean drawShadow) {
return drawStringNoFlush(graphics, graphics.pose().last().pose(), font, component, x, y, color, drawShadow);
}

public static int drawStringNoFlush(GuiGraphics graphics, Matrix4f matrix, Font font, Component component, float x, float y, int color, boolean drawShadow) {
//Copy of GuiGraphics#drawString(Font, FormattedCharSequence, float, float, int, boolean) but without the flush at the end
return font.drawInBatch(component.getVisualOrderText(), x, y, color, drawShadow, matrix, graphics.bufferSource(),
Font.DisplayMode.NORMAL, 0, LightTexture.FULL_BRIGHT);
}

public static void renderItem(GuiGraphics guiGraphics, @NotNull ItemStack stack, int xAxis, int yAxis, float scale, Font font, @Nullable String text, boolean overlay) {
if (!stack.isEmpty()) {
try {
Expand Down
67 changes: 36 additions & 31 deletions src/main/java/mekanism/client/render/HUDRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import java.util.List;
import java.util.function.Predicate;
import mekanism.api.gear.IHUDElement;
import mekanism.api.gear.IModuleContainer;
import mekanism.api.gear.IModuleHelper;
import mekanism.api.text.ILangEntry;
import mekanism.client.gui.GuiUtils;
import mekanism.client.render.hud.MekanismHUD.DelayedString;
import mekanism.common.MekanismLang;
import mekanism.common.config.MekanismConfig;
import mekanism.common.content.gear.HUDElement.HUDColor;
Expand All @@ -30,6 +31,7 @@
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.joml.Matrix4f;

//TODO - 1.20: Decide if we want font rendering in this to support GuiUtils#drawBackdrop and if so how to best go about it
public class HUDRenderer {
Expand All @@ -48,25 +50,24 @@ public class HUDRenderer {
private float prevRotationYaw;
private float prevRotationPitch;

public void renderHUD(Minecraft minecraft, GuiGraphics guiGraphics, Font font, DeltaTracker delta, int screenWidth, int screenHeight, int maxTextHeight,
boolean reverseHud) {
public void renderHUD(Minecraft minecraft, GuiGraphics guiGraphics, Font font, List<DelayedString> delayedDraws, DeltaTracker delta, int screenWidth, int screenHeight,
int maxTextHeight, boolean reverseHud) {
Player player = minecraft.player;
update(minecraft.level, player);
if (MekanismConfig.client.hudOpacity.get() < 0.05F) {
return;
}
int color = HUDColor.REGULAR.getColorARGB();
PoseStack pose = guiGraphics.pose();
pose.pushPose();
float yawJitter = -absSqrt(player.yHeadRot - prevRotationYaw);
float pitchJitter = -absSqrt(player.getXRot() - prevRotationPitch);
pose.translate(yawJitter, pitchJitter, 0);
if (MekanismConfig.client.hudCompassEnabled.get()) {
renderCompass(player, font, guiGraphics, delta, screenWidth, screenHeight, maxTextHeight, reverseHud, color);
renderCompass(player, font, guiGraphics, delayedDraws, delta, screenWidth, screenHeight, maxTextHeight, reverseHud);
}

renderMekaSuitEnergyIcons(player, font, guiGraphics, color);
renderMekaSuitModuleIcons(player, font, guiGraphics, screenWidth, screenHeight, reverseHud, color);
renderMekaSuitEnergyIcons(player, font, guiGraphics, delayedDraws);
renderMekaSuitModuleIcons(player, font, guiGraphics, delayedDraws, screenWidth, screenHeight, reverseHud);

pose.popPose();
}
Expand All @@ -90,37 +91,39 @@ private static float absSqrt(float val) {
return val < 0 ? -ret : ret;
}

private void renderMekaSuitEnergyIcons(Player player, Font font, GuiGraphics guiGraphics, int color) {
private void renderMekaSuitEnergyIcons(Player player, Font font, GuiGraphics guiGraphics, List<DelayedString> delayedDraws) {
PoseStack pose = guiGraphics.pose();
pose.pushPose();
pose.translate(10, 10, 0);
Matrix4f matrix = new Matrix4f(pose.last().pose());
int posX = 0;
Predicate<Item> showArmorPercent = item -> item instanceof ItemMekaSuitArmor;
for (int i = 0; i < EnumUtils.ARMOR_SLOTS.length; i++) {
posX += renderEnergyIcon(player, font, guiGraphics, posX, color, ARMOR_ICONS[i], EnumUtils.ARMOR_SLOTS[i], showArmorPercent);
posX += renderEnergyIcon(player, font, guiGraphics, matrix, delayedDraws, posX, ARMOR_ICONS[i], EnumUtils.ARMOR_SLOTS[i], showArmorPercent);
}
Predicate<Item> showToolPercent = item -> item instanceof ItemMekaTool;
for (EquipmentSlot hand : EnumUtils.HAND_SLOTS) {
posX += renderEnergyIcon(player, font, guiGraphics, posX, color, TOOL_ICON, hand, showToolPercent);
posX += renderEnergyIcon(player, font, guiGraphics, matrix, delayedDraws, posX, TOOL_ICON, hand, showToolPercent);
}
pose.popPose();
}

private int renderEnergyIcon(Player player, Font font, GuiGraphics guiGraphics, int posX, int color, ResourceLocation icon, EquipmentSlot slot,
Predicate<Item> showPercent) {
private int renderEnergyIcon(Player player, Font font, GuiGraphics guiGraphics, Matrix4f matrix, List<DelayedString> delayedDraws, int posX, ResourceLocation icon,
EquipmentSlot slot, Predicate<Item> showPercent) {
ItemStack stack = player.getItemBySlot(slot);
if (showPercent.test(stack.getItem())) {
renderHUDElement(font, guiGraphics, posX, 0, IModuleHelper.INSTANCE.hudElementPercent(icon, StorageUtils.getEnergyRatio(stack)), color, false);
renderHUDElement(font, guiGraphics, matrix, delayedDraws, posX, 0, IModuleHelper.INSTANCE.hudElementPercent(icon, StorageUtils.getEnergyRatio(stack)),
false);
return 48;
}
return 0;
}

private void renderMekaSuitModuleIcons(Player player, Font font, GuiGraphics guiGraphics, int screenWidth, int screenHeight, boolean reverseHud, int color) {
private void renderMekaSuitModuleIcons(Player player, Font font, GuiGraphics guiGraphics, List<DelayedString> delayedDraws, int screenWidth, int screenHeight,
boolean reverseHud) {
int startX = screenWidth - 10;
int curY = screenHeight - 10;
PoseStack pose = guiGraphics.pose();
pose.pushPose();
Matrix4f matrix = new Matrix4f(guiGraphics.pose().last().pose());
//Render any elements that might be on modules in the meka suit while worn or on the meka tool while held
for (EquipmentSlot type : EQUIPMENT_ORDER) {
ItemStack stack = player.getItemBySlot(type);
Expand All @@ -130,30 +133,31 @@ private void renderMekaSuitModuleIcons(Player player, Font font, GuiGraphics gui
curY -= 18;
if (reverseHud) {
//Align the mekasuit module icons to the left of the screen
renderHUDElement(font, guiGraphics, 10, curY, element, color, false);
renderHUDElement(font, guiGraphics, matrix, delayedDraws, 10, curY, element, false);
} else {
//Align the mekasuit module icons to the right of the screen
int elementWidth = 24 + font.width(element.getText());
renderHUDElement(font, guiGraphics, startX - elementWidth, curY, element, color, true);
renderHUDElement(font, guiGraphics, matrix, delayedDraws, startX - elementWidth, curY, element, true);
}
}
}
}
pose.popPose();
}

private void renderHUDElement(Font font, GuiGraphics guiGraphics, int x, int y, IHUDElement element, int color, boolean iconRight) {
private void renderHUDElement(Font font, GuiGraphics guiGraphics, Matrix4f matrix, List<DelayedString> delayedDraws, int x, int y, IHUDElement element,
boolean iconRight) {
int color = element.getColor();
RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
MekanismRenderer.color(guiGraphics, color);
guiGraphics.blit(element.getIcon(), iconRight ? x + font.width(element.getText()) + 2 : x, y, 0, 0, 16, 16, 16, 16);
MekanismRenderer.resetColor(guiGraphics);
//TODO: Batch the string draw calls that are in this class
guiGraphics.drawString(font, element.getText(), iconRight ? x : x + 18, y + 5, element.getColor(), false);
delayedDraws.add(new DelayedString(matrix, element.getText(), iconRight ? x : x + 18, y + 5, color, false));
}

private void renderCompass(Player player, Font font, GuiGraphics guiGraphics, DeltaTracker delta, int screenWidth, int screenHeight, int maxTextHeight,
boolean reverseHud, int color) {
private void renderCompass(Player player, Font font, GuiGraphics guiGraphics, List<DelayedString> delayedDraws, DeltaTracker delta, int screenWidth,
int screenHeight, int maxTextHeight, boolean reverseHud) {
int color = HUDColor.REGULAR.getColorARGB();
//Reversed hud causes the compass to render on the right side of the screen
int posX = reverseHud ? screenWidth - 125 : 25;
//Pin the compass above the bottom of the screen and also above the text hud that may render below it
Expand All @@ -166,32 +170,33 @@ private void renderCompass(Player player, Font font, GuiGraphics guiGraphics, De
pose.pushPose();
pose.scale(0.7F, 0.7F, 0.7F);
Component coords = MekanismLang.GENERIC_BLOCK_POS.translate(player.getBlockX(), player.getBlockY(), player.getBlockZ());
GuiUtils.drawString(guiGraphics, font, coords, -font.width(coords) / 2F, -4, color, false);
delayedDraws.add(new DelayedString(pose, coords, -font.width(coords) / 2F, -4, color, false));
pose.popPose();

float angle = 180 - player.getViewYRot(delta.getGameTimeDeltaPartialTick(false));
pose.mulPose(Axis.XP.rotationDegrees(-60));
pose.mulPose(Axis.ZP.rotationDegrees(angle));
rotateStr(guiGraphics, delayedDraws, MekanismLang.NORTH_SHORT, angle, 0, color);
rotateStr(guiGraphics, delayedDraws, MekanismLang.EAST_SHORT, angle, 90, color);
rotateStr(guiGraphics, delayedDraws, MekanismLang.SOUTH_SHORT, angle, 180, color);
rotateStr(guiGraphics, delayedDraws, MekanismLang.WEST_SHORT, angle, 270, color);

RenderSystem.enableBlend();
RenderSystem.defaultBlendFunc();
MekanismRenderer.color(guiGraphics, color);
guiGraphics.blit(COMPASS, -50, -50, 100, 100, 0, 0, 256, 256, 256, 256);
rotateStr(font, guiGraphics, MekanismLang.NORTH_SHORT, angle, 0, color);
rotateStr(font, guiGraphics, MekanismLang.EAST_SHORT, angle, 90, color);
rotateStr(font, guiGraphics, MekanismLang.SOUTH_SHORT, angle, 180, color);
rotateStr(font, guiGraphics, MekanismLang.WEST_SHORT, angle, 270, color);
MekanismRenderer.resetColor(guiGraphics);
pose.popPose();
pose.popPose();
}

private void rotateStr(Font font, GuiGraphics guiGraphics, ILangEntry langEntry, float rotation, float shift, int color) {
private void rotateStr(GuiGraphics guiGraphics, List<DelayedString> delayedDraws, ILangEntry langEntry, float rotation, float shift, int color) {
PoseStack pose = guiGraphics.pose();
pose.pushPose();
pose.mulPose(Axis.ZP.rotationDegrees(shift));
pose.translate(0, -50, 0);
pose.mulPose(Axis.ZP.rotationDegrees(-rotation - shift));
GuiUtils.drawString(guiGraphics, font, langEntry.translate(), -2.5F, -4, color, false);
delayedDraws.add(new DelayedString(pose, langEntry.translate(), -2.5F, -4, color, false));
pose.popPose();
}
}
31 changes: 29 additions & 2 deletions src/main/java/mekanism/client/render/hud/MekanismHUD.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import net.neoforged.neoforge.items.IItemHandler;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;

public class MekanismHUD implements LayeredDraw.Layer {

Expand Down Expand Up @@ -78,9 +79,12 @@ public void render(@NotNull GuiGraphics graphics, @NotNull DeltaTracker delta) {
}
}
Font font = minecraft.font;
List<DelayedString> delayedDraws = null;

boolean reverseHud = MekanismConfig.client.reverseHUD.get();
int maxTextHeight = graphics.guiHeight();
if (count > 0) {
delayedDraws = new ArrayList<>();
float hudScale = MekanismConfig.client.hudScale.get();
int xScale = (int) (graphics.guiWidth() / hudScale);
int yScale = (int) (graphics.guiHeight() / hudScale);
Expand Down Expand Up @@ -108,13 +112,14 @@ public void render(@NotNull GuiGraphics graphics, @NotNull DeltaTracker delta) {
GuiUtils.drawBackdrop(graphics, Minecraft.getInstance(), x, y, maxTextWidth, maxTextHeight, 0xFFFFFFFF);
}

Matrix4f matrix = new Matrix4f(pose.last().pose());
for (List<Component> group : renderStrings) {
for (Component text : group) {
int textWidth = font.width(text);
//Align text to right if hud is reversed, otherwise align to the left
//Note: that we always offset by 2 pixels from the edge of the screen regardless of how it is aligned
int x = reverseHud ? xScale - textWidth - 2 : 2;
graphics.drawString(font, text, x, y, 0xFFC8C8C8);
delayedDraws.add(new DelayedString(matrix, text, x, y, 0xFFC8C8C8, true));
y += 9;
}
y += 2;
Expand All @@ -123,7 +128,18 @@ public void render(@NotNull GuiGraphics graphics, @NotNull DeltaTracker delta) {
}

if (player.getItemBySlot(EquipmentSlot.HEAD).is(MekanismTags.Items.MEKASUIT_HUD_RENDERER)) {
hudRenderer.renderHUD(minecraft, graphics, font, delta, graphics.guiWidth(), graphics.guiHeight(), maxTextHeight, reverseHud);
if (delayedDraws == null) {
delayedDraws = new ArrayList<>();
}
hudRenderer.renderHUD(minecraft, graphics, font, delayedDraws, delta, graphics.guiWidth(), graphics.guiHeight(), maxTextHeight, reverseHud);
}

if (delayedDraws != null && !delayedDraws.isEmpty()) {
for (DelayedString delayedDraw : delayedDraws) {
delayedDraw.draw(graphics, font);
}
//Flush once at the end of the draws
graphics.flush();
}
}
}
Expand All @@ -143,4 +159,15 @@ private interface HudComponentBuilder {

void add(IItemHUDProvider hudProvider, List<Component> existing, Player player, ItemStack stack, EquipmentSlot slot);
}

public record DelayedString(Matrix4f matrix, Component component, float x, float y, int color, boolean dropShadow) {

public DelayedString(PoseStack pose, Component component, float x, float y, int color, boolean dropShadow) {
this(new Matrix4f(pose.last().pose()), component, x, y, color, dropShadow);
}

public void draw(GuiGraphics graphics, Font font) {
GuiUtils.drawStringNoFlush(graphics, matrix, font, component, x, y, color, dropShadow);
}
}
}

0 comments on commit c364e7f

Please sign in to comment.