package micdoodle8.mods.galacticraft.core.client.screen; import micdoodle8.mods.galacticraft.api.client.IGameScreen; import micdoodle8.mods.galacticraft.api.client.IScreenManager; import micdoodle8.mods.galacticraft.api.entity.ITelemetry; import micdoodle8.mods.galacticraft.core.tile.TileEntityTelemetry; import micdoodle8.mods.galacticraft.core.util.ColorUtil; import micdoodle8.mods.galacticraft.core.util.GCCoreUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.EntityOtherPlayerMP; import net.minecraft.client.renderer.OpenGlHelper; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.entity.Render; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.monster.EntitySkeleton; import net.minecraft.entity.monster.EntityZombie; import net.minecraft.entity.passive.*; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.EnumDyeColor; import net.minecraft.world.World; import net.minecraftforge.fml.client.FMLClientHandler; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.lwjgl.BufferUtils; import org.lwjgl.opengl.GL11; import org.lwjgl.opengl.GL12; import java.nio.DoubleBuffer; public class GameScreenText implements IGameScreen { private float frameA; private float frameBx; private float frameBy; private int yPos; private DoubleBuffer planes; public GameScreenText() { if (GCCoreUtil.getEffectiveSide().isClient()) { planes = BufferUtils.createDoubleBuffer(4 * Double.SIZE); } } @Override public void setFrameSize(float frameSize) { this.frameA = frameSize; } @Override @SideOnly(Side.CLIENT) public void render(int type, float ticks, float sizeX, float sizeY, IScreenManager scr) { DrawGameScreen screen = (DrawGameScreen) scr; frameBx = sizeX - frameA; frameBy = sizeY - frameA; drawBlackBackground(0.0F); planeEquation(frameA, frameA, 0, frameA, frameBy, 0, frameA, frameBy, 1); GL11.glClipPlane(GL11.GL_CLIP_PLANE0, planes); GL11.glEnable(GL11.GL_CLIP_PLANE0); planeEquation(frameBx, frameBy, 0, frameBx, frameA, 0, frameBx, frameA, 1); GL11.glClipPlane(GL11.GL_CLIP_PLANE1, planes); GL11.glEnable(GL11.GL_CLIP_PLANE1); planeEquation(frameA, frameBy, 0, frameBx, frameBy, 0, frameBx, frameBy, 1); GL11.glClipPlane(GL11.GL_CLIP_PLANE2, planes); GL11.glEnable(GL11.GL_CLIP_PLANE2); planeEquation(frameBx, frameA, 0, frameA, frameA, 0, frameA, frameA, 1); GL11.glClipPlane(GL11.GL_CLIP_PLANE3, planes); GL11.glEnable(GL11.GL_CLIP_PLANE3); yPos = 0; TileEntityTelemetry telemeter = TileEntityTelemetry.getNearest(screen.driver); //Make the text to draw. To look good it's important the width and height //of the whole text box are correctly set here. String strName = ""; String[] str = { GCCoreUtil.translate("gui.display.nolink"), "", "", "", "" }; Render renderEntity = null; Entity entity = null; float Xmargin = 0; if (telemeter != null && telemeter.clientData.length >= 3) { if (telemeter.clientClass != null) { if (telemeter.clientClass == screen.telemetryLastClass && (telemeter.clientClass != EntityPlayerMP.class || telemeter.clientName.equals(screen.telemetryLastName))) { //Used cached data from last time if possible entity = screen.telemetryLastEntity; renderEntity = screen.telemetryLastRender; strName = screen.telemetryLastName; } else { //Create an entity to render, based on class, and get its name entity = null; if (telemeter.clientClass == EntityPlayerMP.class) { strName = telemeter.clientName; entity = new EntityOtherPlayerMP(screen.driver.getWorld(), telemeter.clientGameProfile); renderEntity = (Render) FMLClientHandler.instance().getClient().getRenderManager().entityRenderMap.get(EntityPlayer.class); } else { try { entity = (Entity) telemeter.clientClass.getConstructor(World.class).newInstance(screen.driver.getWorld()); } catch (Exception ex) { } if (entity != null) { strName = entity.getName(); } renderEntity = (Render) FMLClientHandler.instance().getClient().getRenderManager().entityRenderMap.get(telemeter.clientClass); } } //Setup special visual types from data sent by Telemetry if (entity instanceof EntityHorse) { ((EntityHorse) entity).setHorseType(telemeter.clientData[3]); ((EntityHorse) entity).setHorseVariant(telemeter.clientData[4]); } if (entity instanceof EntityVillager) { ((EntityVillager) entity).setProfession(telemeter.clientData[3]); ((EntityVillager) entity).setGrowingAge(telemeter.clientData[4]); } else if (entity instanceof EntityWolf) { ((EntityWolf) entity).setCollarColor(EnumDyeColor.byDyeDamage(telemeter.clientData[3])); ((EntityWolf) entity).setBegging(telemeter.clientData[4] == 1); } else if (entity instanceof EntitySheep) { ((EntitySheep) entity).setFleeceColor(EnumDyeColor.byDyeDamage(telemeter.clientData[3])); ((EntitySheep) entity).setSheared(telemeter.clientData[4] == 1); } else if (entity instanceof EntityOcelot) { ((EntityOcelot) entity).setTameSkin(telemeter.clientData[3]); } else if (entity instanceof EntitySkeleton) { ((EntitySkeleton) entity).setSkeletonType(telemeter.clientData[3]); } else if (entity instanceof EntityZombie) { ((EntityZombie) entity).setVillager(telemeter.clientData[3] == 1); ((EntityZombie) entity).setChild(telemeter.clientData[4] == 1); } } if (entity instanceof ITelemetry) { ((ITelemetry) entity).receiveData(telemeter.clientData, str); } else if (entity instanceof EntityLivingBase) { //Living entity: // data0 = time to show red damage // data1 = health in half-hearts // data2 = pulse // data3 = hunger (for player); horsetype (for horse) // data4 = oxygen (for player); horsevariant (for horse) str[0] = telemeter.clientData[0] > 0 ? GCCoreUtil.translate("gui.player.ouch") : ""; if (telemeter.clientData[1] >= 0) { str[1] = GCCoreUtil.translate("gui.player.health") + ": " + telemeter.clientData[1] + "%"; } else { str[1] = ""; } str[2] = "" + telemeter.clientData[2] + " " + GCCoreUtil.translate("gui.player.bpm"); if (telemeter.clientData[3] > -1) { str[3] = GCCoreUtil.translate("gui.player.food") + ": " + telemeter.clientData[3] + "%"; } if (telemeter.clientData[4] > -1) { int oxygen = telemeter.clientData[4]; oxygen = (oxygen % 4096) + (oxygen / 4096); if (oxygen == 180 || oxygen == 90) { str[4] = GCCoreUtil.translate("gui.oxygen_storage.desc.1") + ": OK"; } else { str[4] = GCCoreUtil.translate("gui.oxygen_storage.desc.1") + ": " + this.makeOxygenString(oxygen) + GCCoreUtil.translate("gui.seconds"); } } } else //Generic - could be boats or minecarts etc - just show the speed //TODO can add more here, e.g. position data? if (telemeter.clientData[2] >= 0) { str[2] = makeSpeedString(telemeter.clientData[2]); } } else { //Default - draw a simple time display just to show the Display Screen is working World w1 = screen.driver.getWorld(); int time1 = w1 != null ? (int) ((w1.getWorldTime() + 6000L) % 24000L) : 0; str[2] = makeTimeString(time1 * 360); } int textWidthPixels = 155; int textHeightPixels = 60; //1 lines if (str[3].isEmpty()) { textHeightPixels -= 10; } if (str[4].isEmpty()) { textHeightPixels -= 10; } //First pass - approximate border size float borders = frameA * 2 + 0.05F * Math.min(sizeX, sizeY); float scaleXTest = (sizeX - borders) / textWidthPixels; float scaleYTest = (sizeY - borders) / textHeightPixels; float scale = sizeX; if (scaleYTest < scaleXTest) { scale = sizeY; } //Second pass - the border size may be more accurate now borders = frameA * 2 + 0.05F * scale; scaleXTest = (sizeX - borders) / textWidthPixels; scaleYTest = (sizeY - borders) / textHeightPixels; scale = sizeX; float scaleText = scaleXTest; if (scaleYTest < scaleXTest) { scale = sizeY; scaleText = scaleYTest; } //Centre the text in the display float border = frameA + 0.025F * scale; if (entity != null && renderEntity != null) { Xmargin = (sizeX - borders) / 2; } float Xoffset = (sizeX - borders - textWidthPixels * scaleText) / 2 + Xmargin; float Yoffset = (sizeY - borders - textHeightPixels * scaleText) / 2 + scaleText; GL11.glTranslatef(border + Xoffset, border + Yoffset, 0.0F); GL11.glScalef(scaleText, scaleText, 1.0F); //Actually draw the text int whiteColour = ColorUtil.to32BitColor(255, 240, 216, 255); drawText(strName, whiteColour); drawText(str[0], whiteColour); drawText(str[1], whiteColour); drawText(str[2], whiteColour); drawText(str[3], whiteColour); drawText(str[4], whiteColour); //If there is an entity to render, draw it on the left of the text if (renderEntity != null && entity != null) { GL11.glTranslatef(-Xmargin / 2 / scaleText, textHeightPixels / 2 + (-Yoffset + (sizeY - borders) / 2) / scaleText, -0.0005F); float scalefactor = 38F / (float) Math.pow(Math.max(entity.height, entity.width), 0.65); GL11.glScalef(scalefactor, scalefactor, 0.0015F); GL11.glRotatef(180F, 0, 0, 1); GL11.glRotatef(180F, 0, 1, 0); if (entity instanceof ITelemetry) { ((ITelemetry) entity).adjustDisplay(telemeter.clientData); } // RenderPlayerGC.flagThermalOverride = true; // renderEntity.doRender(entity, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F); TODO // RenderPlayerGC.flagThermalOverride = false; GL11.glEnable(GL12.GL_RESCALE_NORMAL); OpenGlHelper.setActiveTexture(OpenGlHelper.lightmapTexUnit); GL11.glDisable(GL11.GL_TEXTURE_2D); OpenGlHelper.setActiveTexture(OpenGlHelper.defaultTexUnit); } //TODO Cross-dimensional tracking (i.e. old entity setDead, new entity created) //TODO Deal with text off screen (including where localizations longer than English) screen.telemetryLastClass = (telemeter == null) ? null : telemeter.clientClass; screen.telemetryLastEntity = entity; screen.telemetryLastRender = renderEntity; screen.telemetryLastName = strName; GL11.glDisable(GL11.GL_CLIP_PLANE3); GL11.glDisable(GL11.GL_CLIP_PLANE2); GL11.glDisable(GL11.GL_CLIP_PLANE1); GL11.glDisable(GL11.GL_CLIP_PLANE0); } private String makeTimeString(int l) { int hrs = l / 360000; int mins = l / 6000 - hrs * 60; int secs = l / 100 - hrs * 3600 - mins * 60; String hrsStr = hrs > 9 ? "" + hrs : "0" + hrs; String minsStr = mins > 9 ? "" + mins : "0" + mins; String secsStr = secs > 9 ? "" + secs : "0" + secs; return hrsStr + ":" + minsStr + ":" + secsStr; } public static String makeSpeedString(int speed100) { int sp1 = speed100 / 100; int sp2 = (speed100 % 100); String spstr1 = GCCoreUtil.translate("gui.rocket.speed") + ": " + sp1; String spstr2 = (sp2 > 9 ? "" : "0") + sp2; return spstr1 + "." + spstr2 + " " + GCCoreUtil.translate("gui.lander.velocityu"); } private String makeHealthString(int hearts2) { int sp1 = hearts2 / 2; int sp2 = (hearts2 % 2) * 5; String spstr1 = "" + sp1; String spstr2 = "" + sp2; return spstr1 + "." + spstr2 + " hearts"; } private String makeOxygenString(int oxygen) { //Server takes 1 air away every 9 ticks (OxygenUtil.getDrainSpacing) int sp1 = oxygen * 9 / 20; int sp2 = ((oxygen * 9) % 20) / 2; String spstr1 = "" + sp1; String spstr2 = "" + sp2; return spstr1 + "." + spstr2; } private void drawText(String str, int colour) { Minecraft.getMinecraft().fontRendererObj.drawString(str, 0, yPos, colour, false); yPos += 10; } private void drawBlackBackground(float greyLevel) { GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GL11.glDisable(GL11.GL_TEXTURE_2D); final Tessellator tess = Tessellator.getInstance(); WorldRenderer worldRenderer = tess.getWorldRenderer(); GL11.glColor4f(greyLevel, greyLevel, greyLevel, 1.0F); worldRenderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION); worldRenderer.pos(frameA, frameBy, 0.005F).endVertex(); worldRenderer.pos(frameBx, frameBy, 0.005F).endVertex(); worldRenderer.pos(frameBx, frameA, 0.005F).endVertex(); worldRenderer.pos(frameA, frameA, 0.005F).endVertex(); tess.draw(); GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); GL11.glEnable(GL11.GL_TEXTURE_2D); } private void planeEquation(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3) { double[] result = new double[4]; result[0] = y1 * (z2 - z3) + y2 * (z3 - z1) + y3 * (z1 - z2); result[1] = z1 * (x2 - x3) + z2 * (x3 - x1) + z3 * (x1 - x2); result[2] = x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2); result[3] = -(x1 * (y2 * z3 - y3 * z2) + x2 * (y3 * z1 - y1 * z3) + x3 * (y1 * z2 - y2 * z1)); planes.put(result, 0, 4); planes.position(0); } }