package net.rustnotmc.client; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.rustnotmc.api.hud.HudSurface; /** * The game's implementation of the mod HUD surface. * * A mod draws through this interface and never touches a game type, which is * what lets the layout and the overlay code be tested with the game closed. The * reverse cost is paid once, here: everything a mod needs from Minecraft is * resolved in this class. * * Coordinates are the scaled interface ones, so an element lines up with the * health bar and the chat without the mod knowing about GUI scale. * * Lives in game-fork/src-overlay; src is regenerated on every build. */ public final class RsxHudSurface implements HudSurface { private final Minecraft minecraft; /** * Rebuilt only when the window or the scale factor actually changes. A new * ScaledResolution per frame would be one short-lived object sixty times a * second for a value that is almost never different. */ private ScaledResolution resolution; private int cachedWidth = -1; private int cachedHeight = -1; private int cachedScale = -1; public RsxHudSurface(Minecraft minecraft) { this.minecraft = minecraft; } private ScaledResolution resolution() { int width = this.minecraft.displayWidth; int height = this.minecraft.displayHeight; int scale = this.minecraft.gameSettings.guiScale; if (this.resolution == null || width != this.cachedWidth || height != this.cachedHeight || scale != this.cachedScale) { this.resolution = new ScaledResolution(this.minecraft); this.cachedWidth = width; this.cachedHeight = height; this.cachedScale = scale; } return this.resolution; } @Override public boolean available() { return this.minecraft != null && this.minecraft.fontRenderer != null; } @Override public int width() { return this.available() ? resolution().getScaledWidth() : 0; } @Override public int height() { return this.available() ? resolution().getScaledHeight() : 0; } @Override public float scale() { return (float) resolution().getScaleFactor(); } @Override public void rect(float x, float y, float w, float h, int rgb, float alpha) { if (w <= 0.0F || h <= 0.0F) { return; } int a = clampAlpha(alpha); int r = (rgb >> 16) & 0xFF; int g = (rgb >> 8) & 0xFF; int b = rgb & 0xFF; // the vanilla debug overlay draws coloured quads the same way; this // GlStateManager has no isTextureEnabled to ask, so the state is set // explicitly the way the game itself does it GlStateManager.disableTexture2D(); Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); buffer.begin(7, DefaultVertexFormats.POSITION_COLOR); buffer.pos(x, y + h, 0.0D).color(r, g, b, a).endVertex(); buffer.pos(x + w, y + h, 0.0D).color(r, g, b, a).endVertex(); buffer.pos(x + w, y, 0.0D).color(r, g, b, a).endVertex(); buffer.pos(x, y, 0.0D).color(r, g, b, a).endVertex(); tessellator.draw(); GlStateManager.enableTexture2D(); } @Override public void text(float x, float y, String value, int rgb, float alpha) { if (value == null || value.isEmpty() || !this.available()) { return; } GlStateManager.enableTexture2D(); this.minecraft.fontRenderer.drawStringWithShadow( value, x, y, (rgb & 0x00FFFFFF) | (clampAlpha(alpha) << 24)); } @Override public float textWidth(String value) { if (value == null || value.isEmpty() || !this.available()) { return 0.0F; } return (float) this.minecraft.fontRenderer.getStringWidth(value); } @Override public int textHeight() { return this.available() ? this.minecraft.fontRenderer.FONT_HEIGHT : 0; } private static int clampAlpha(float alpha) { if (alpha < 0.0F) { return 0; } if (alpha > 1.0F) { return 255; } return (int) (alpha * 255.0F + 0.5F); } }