package speedytools.clientside.rendering; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.entity.player.EntityPlayer; import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.fml.common.eventhandler.Event; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import speedytools.clientside.ClientSide; import speedytools.common.utilities.Colour; import speedytools.common.utilities.UsefulFunctions; import java.util.ArrayList; import java.util.Collection; /** * User: The Grey Ghost * Date: 22/06/2014 */ public class RendererStatusMessage implements RendererElement { public RendererStatusMessage(StatusMessageRenderInfoUpdateLink i_infoProvider) { infoProvider = i_infoProvider; renderInfo = new StatusMessageRenderInfo(); animationState = AnimationState.NONE; } // @Override // public boolean renderInThisPhase(RenderPhase renderPhase) { // return (renderPhase == RenderPhase.CROSSHAIRS); // } @Override public Collection<Class<? extends Event>> eventsToReceive() { ArrayList<Class<? extends Event>> retval = new ArrayList<Class<? extends Event>>(); retval.add(RenderGameOverlayCrosshairsEvent.class); return retval; } @Override public void render(Event event, float partialTick) { RenderGameOverlayCrosshairsEvent fullEvent = (RenderGameOverlayCrosshairsEvent)event; renderOverlay(fullEvent.resolution, ClientSide.getGlobalTickCount(), partialTick); } // @Override // public void renderWorld(RenderPhase renderPhase, EntityPlayer player, int animationTickCount, float partialTick) { // assert false : "invalid render phase: " + renderPhase; // } public void renderOverlay(ScaledResolution scaledResolution, int animationTickCount, float partialTick) { final double FADE_IN_DURATION_TICKS = 20; final double FADE_OUT_DURATION_TICKS = 10; // if (renderPhase != RenderPhase.CROSSHAIRS) return; boolean shouldIRender = infoProvider.refreshRenderInfo(renderInfo); if (!shouldIRender) return; boolean newMessageArrived = false; if (!renderInfo.messageToDisplay.isEmpty() && !renderInfo.messageToDisplay.equals(currentlyDisplayedMessage)) { newMessageArrived = true; } double animationCounter = animationTickCount + (double) partialTick; if (newMessageArrived) { // don't start a new message until the old one has faded out if (animationState == AnimationState.NONE) { startMessageFadeIn(renderInfo.messageToDisplay, animationCounter); } } else if (renderInfo.messageToDisplay.isEmpty()) { if (animationState != AnimationState.NONE && animationState != AnimationState.FADE_OUT) { startMessageFadeOut(animationCounter); } } final double OPACITY_MIN = 0.2; final double OPACITY_MAX = 1.0; double opacity = OPACITY_MIN; switch (animationState) { case NONE: { currentlyDisplayedMessage = ""; return; } case FADE_IN: { if (animationCounter >= animationFadeInStartCounter + FADE_IN_DURATION_TICKS) { animationState = AnimationState.SUSTAIN; } opacity = UsefulFunctions.interpolate(animationCounter, animationFadeInStartCounter, animationFadeInStartCounter + FADE_IN_DURATION_TICKS, OPACITY_MIN, OPACITY_MAX); break; } case FADE_OUT: { if (animationCounter >= animationFadeOutStartCounter + FADE_OUT_DURATION_TICKS) { animationState = AnimationState.NONE; } opacity = UsefulFunctions.interpolate(animationCounter, animationFadeOutStartCounter, animationFadeOutStartCounter + FADE_OUT_DURATION_TICKS, OPACITY_MAX, OPACITY_MIN); break; } case SUSTAIN: { opacity = OPACITY_MAX; break; } default: assert false : "Invalid animationState " + animationState + " in RendererStatusMessage"; } int width = scaledResolution.getScaledWidth(); int height = scaledResolution.getScaledHeight(); int textColour = Colour.WHITE_40.getColourForFontRenderer(opacity); final int MESSAGE_HEIGHT_OFFSET = 8; drawHoveringText(currentlyDisplayedMessage, width/2, height/2 + MESSAGE_HEIGHT_OFFSET, textColour); } /** * draw hovering text centred at x, y */ private void drawHoveringText(String message, int x, int y, int rgba) { if (message.isEmpty()) return; FontRenderer font = Minecraft.getMinecraft().fontRendererObj; try { GL11.glPushAttrib(GL11.GL_ENABLE_BIT); GL11.glPushMatrix(); GL11.glDisable(GL12.GL_RESCALE_NORMAL); RenderHelper.disableStandardItemLighting(); GL11.glDisable(GL11.GL_LIGHTING); GL11.glDisable(GL11.GL_DEPTH_TEST); int stringWidth = font.getStringWidth(message); font.drawStringWithShadow(message, x - stringWidth / 2, y, rgba); } finally { RenderHelper.enableStandardItemLighting(); GL11.glPopMatrix(); GL11.glPopAttrib(); } } private void startMessageFadeOut(double animationCounter) { animationFadeOutStartCounter = animationCounter; animationState = AnimationState.FADE_OUT; } private void startMessageFadeIn(String newMessage, double animationCounter) { currentlyDisplayedMessage = newMessage; animationFadeInStartCounter = animationCounter; animationState = AnimationState.FADE_IN; } /** * The StatusMessageRenderInfoUpdateLink and StatusMessageRenderInfo are used to retrieve the necessary information for rendering from the current tool * If refreshRenderInfo returns false, no render is performed. */ public interface StatusMessageRenderInfoUpdateLink { public boolean refreshRenderInfo(StatusMessageRenderInfo infoToUpdate); } public static class StatusMessageRenderInfo { public String messageToDisplay; // empty for none } private StatusMessageRenderInfoUpdateLink infoProvider; private StatusMessageRenderInfo renderInfo; private AnimationState animationState; private String currentlyDisplayedMessage; private double animationFadeInStartCounter; private double animationFadeOutStartCounter; private enum AnimationState { NONE, FADE_IN, SUSTAIN, FADE_OUT; } }