diff --git a/src/main/java/ebf/tim/render/BlockTESR.java b/src/main/java/ebf/tim/render/BlockTESR.java new file mode 100644 index 0000000000..9acab83900 --- /dev/null +++ b/src/main/java/ebf/tim/render/BlockTESR.java @@ -0,0 +1,18 @@ +package ebf.tim.render; + +import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; +import net.minecraft.tileentity.TileEntity; +import org.lwjgl.opengl.GL11; + +public class BlockTESR extends TileEntitySpecialRenderer { + + @Override + public void renderTileEntityAt(TileEntity tileEntity, double x, double y, double z, float tick) { + GL11.glPushMatrix(); + if(tileEntity.getWorldObj()!=null) { + GL11.glTranslated(x, y, z); + } + tileEntity.func_145828_a(null); + GL11.glPopMatrix(); + } +} \ No newline at end of file diff --git a/src/main/java/ebf/tim/utility/BitList.java b/src/main/java/ebf/tim/utility/BitList.java new file mode 100644 index 0000000000..9f10790da5 --- /dev/null +++ b/src/main/java/ebf/tim/utility/BitList.java @@ -0,0 +1,77 @@ +package ebf.tim.utility; + +/** + *

bit management

+ * stores a list of bits (booleans), and converts them to a single int for efficient networking transfer. + * Currently has 16 values but can be increased to 32 without any actual problems. + * @author Eternal Blue Flame + */ +public class BitList { + private boolean[] bits = new boolean[]{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}; + + /*get a value in the array, index must be between 0 and 15*/ + public boolean get(int index){ + return bits[index]; + } + /*set a value in the array, index must be between - and 15*/ + public void set(int index, boolean value){ + bits[index]= value; + } + /*set the value of the array to the last 16 bits of an integer*/ + public void set(int value){ + for (int i=0; i<16; i++){ + //<< gets the bit from end to start at the position of i, for example 0 is the last bit, but 1 is second to last. + // & is to get the bits from value + bits[i]= (value & (1 << i)) != 0; + } + } + /*set the value of the array from an array of bytes*/ + public void set(byte[] values){ + for (int i=0; i<16; i++){ + if(values.length>i) { + bits[i] = values[i] == 1; + } + } + } + + public byte[] getBits() { + byte[] value= new byte[bits.length]; + for(int i=0; i loggedLangChecks = new ArrayList<>(); + + private static Minecraft getMC(){return Minecraft.getMinecraft();} + + public static int percentTop(int value, float guiTop){return (int)(guiTop*(value*0.01f));} + public static int percentLeft(int value, float guiLeft){return (int)(guiLeft*(value*0.01f));} + + + public static void drawSlots(List slots, List overlays, List slotX, List slotY, int mouseX, int mouseY, float guiLeft, float guiTop, RenderItem itemRender){ + + GL11.glPushMatrix(); + TextureManager.bindTexture(vanillaInventory); + GL11.glDisable(GL11.GL_LIGHTING); + int i=0; + for (;ix && mouseXy && mouseY Minecraft.getMinecraft().displayWidth/2) { + j2 -= 16 + k; + } + + if (k2 + i1 + 6 > Minecraft.getMinecraft().displayHeight) { + k2 -= 6; + } + + GL11.glTranslatef(0,0,1); + int j1 = -267386864; + drawGradientRect(j2 - 3, k2 - 4, j2 + k + 3, k2 - 3, j1, j1); + drawGradientRect(j2 - 3, k2 + i1 + 3, j2 + k + 3, k2 + i1 + 4, j1, j1); + drawGradientRect(j2 - 3, k2 - 3, j2 + k + 3, k2 + i1 + 3, j1, j1); + drawGradientRect(j2 - 4, k2 - 3, j2 - 3, k2 + i1 + 3, j1, j1); + drawGradientRect(j2 + k + 3, k2 - 3, j2 + k + 4, k2 + i1 + 3, j1, j1); + int k1 = 1347420415; + int l1 = (k1 & 16711422) >> 1 | k1 & -16777216; + drawGradientRect(j2 - 3, k2 - 3 + 1, j2 - 3 + 1, k2 + i1 + 3 - 1, k1, l1); + drawGradientRect(j2 + k + 2, k2 - 3 + 1, j2 + k + 3, k2 + i1 + 3 - 1, k1, l1); + drawGradientRect(j2 - 3, k2 - 3, j2 + k + 3, k2 - 3 + 1, k1, k1); + drawGradientRect(j2 - 3, k2 + i1 + 2, j2 + k + 3, k2 + i1 + 3, l1, l1); + GL11.glEnable(GL11.GL_TEXTURE_2D); + + GL11.glTranslatef(0,0,400); + Minecraft.getMinecraft().fontRenderer.drawStringWithShadow(str, j2, k2, -1); + + GL11.glEnable(GL11.GL_LIGHTING); + RenderHelper.enableStandardItemLighting(); + GL11.glEnable(GL12.GL_RESCALE_NORMAL); + } + + + /** + * A more heavily optimized method to render text with outlines + * done by rendering once to a displaylist, then just re-rendering the displaylist with offsets to make an outline. + * + * @param font the fontRender, usually from the MC instance, but custom can be supplied. + * @param string the string of text to display + * @param x the x coord to draw at, this is not relative to the screen center. + * @param y the x coord to draw at, this is not relative to the screen center. + * @param color the hex value color to draw the center string + */ + public static void drawTextOutlined(FontRenderer font, String string, float x, float y, int color){ + GL11.glPushMatrix(); + int i= GLAllocation.generateDisplayLists(1); + GL11.glNewList(i, GL11.GL_COMPILE); + //render once, then translate around a 3x3 square. + font.drawString(string, (int)x-1, (int)y+1, 0); + GL11.glEndList(); + GL11.glTranslatef(1,0,0); + GL11.glCallList(i); + GL11.glTranslatef(1,0,0); + GL11.glCallList(i); + GL11.glTranslatef(0,-1,0); + GL11.glCallList(i); + GL11.glTranslatef(0,-1,0); + GL11.glCallList(i); + GL11.glTranslatef(-1,0,0); + GL11.glCallList(i); + GL11.glTranslatef(-1,0,0); + GL11.glCallList(i); + GL11.glTranslatef(0,1,0); + GL11.glCallList(i); + GL11.glTranslatef(0,1,0); + GL11.glCallList(i); + + font.drawString(string,(int)x,(int)y,color); + GL11.glColor4f(1,1,1,1);//fixes color bleed + GL11.glPopMatrix(); + GL11.glDeleteLists(i,1);//we don't need it later, clear it from GPU + } + + + + + /**the amount to scale the GUI by, same as vanilla*/ + private static final float guiScaler = 0.00390625F; + /** + *

Draw Texture

+ * This replaces the base class and allows us to draw textures that are stretched to the shape defined in a more efficient manner. + * NOTE: all textures must be divisible by 256x256 + * @param posX the X position on screen to draw at. + * @param posY the Y position on screen to draw at. + * @param posU the X position of the texture to start from. + * @param posV the Y position of the texture to start from. + * @param width the width of the box. + * @param height the height of the box. + * @param widthUV defines the X size of the texture part used + * @param heightUV defines the X Y size of the texture part used + */ + public static void drawTexturedRect(float posX, float posY, int posU, int posV, int width, int height, int widthUV, int heightUV) { + Tessellator tessellator = Tessellator.getInstance(); + tessellator.startDrawing(GL11.GL_QUADS); + tessellator.addVertexWithUV(posX, posY + height, 0, posU * guiScaler, (posV + heightUV) * guiScaler); + tessellator.addVertexWithUV(posX + width, posY + height, 0, (posU + widthUV) * guiScaler, (posV + heightUV) * guiScaler); + tessellator.addVertexWithUV(posX + width, posY, 0, (posU + widthUV) * guiScaler, posV * guiScaler); + tessellator.addVertexWithUV(posX, posY, 0, posU * guiScaler, posV * guiScaler); + tessellator.draw(); + } + public static void drawTexturedRect(float posX, float posY, int posU, int posV, int width, int height) { + Tessellator tessellator = Tessellator.getInstance(); + tessellator.startDrawing(GL11.GL_QUADS); + tessellator.addVertexWithUV(posX, posY + height, 0, posU * guiScaler, (posV + height) * guiScaler); + tessellator.addVertexWithUV(posX + width, posY + height, 0, (posU + width) * guiScaler, (posV + height) * guiScaler); + tessellator.addVertexWithUV(posX + width, posY, 0, (posU + width) * guiScaler, posV * guiScaler); + tessellator.addVertexWithUV(posX, posY, 0, posU * guiScaler, posV * guiScaler); + tessellator.draw(); + } + + public static void drawGradientRect(int p_73733_1_, int p_73733_2_, int p_73733_3_, int p_73733_4_, int p_73733_5_, int p_73733_6_) { + float f = (p_73733_5_ >> 24 & 255) / 255.0F; + float f1 = (p_73733_5_ >> 16 & 255) / 255.0F; + float f2 = (p_73733_5_ >> 8 & 255) / 255.0F; + float f3 = (p_73733_5_ & 255) / 255.0F; + float f4 = (p_73733_6_ >> 24 & 255) / 255.0F; + float f5 = (p_73733_6_ >> 16 & 255) / 255.0F; + float f6 = (p_73733_6_ >> 8 & 255) / 255.0F; + float f7 = (p_73733_6_ & 255) / 255.0F; + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_BLEND); + GL11.glDisable(GL11.GL_ALPHA_TEST); + OpenGlHelper.glBlendFunc(770, 771, 1, 0); + GL11.glShadeModel(GL11.GL_SMOOTH); + net.minecraft.client.renderer.Tessellator tessellator = net.minecraft.client.renderer.Tessellator.instance; + tessellator.startDrawingQuads(); + tessellator.setColorRGBA_F(f1, f2, f3, f); + tessellator.addVertex(p_73733_3_, p_73733_2_, 300); + tessellator.addVertex(p_73733_1_, p_73733_2_, 300); + tessellator.setColorRGBA_F(f5, f6, f7, f4); + tessellator.addVertex(p_73733_1_, p_73733_4_, 300); + tessellator.addVertex(p_73733_3_, p_73733_4_, 300); + tessellator.draw(); + GL11.glShadeModel(GL11.GL_FLAT); + GL11.glDisable(GL11.GL_BLEND); + GL11.glEnable(GL11.GL_ALPHA_TEST); + GL11.glEnable(GL11.GL_TEXTURE_2D); + } + + public static String translate(String text){ + if (StatCollector.translateToLocal(text).equals(text)){ + if(!loggedLangChecks.contains(text)) { + DebugUtil.println("Missing lang entry for: ", text, Thread.currentThread().getStackTrace()[2]); + loggedLangChecks.add(text); + } + return text; + } else { + return StatCollector.translateToLocal(text); + } + } + + public static void fixItemLighting(World w){ + if(w==null){ + Minecraft.getMinecraft().entityRenderer.disableLightmap(1D); + } + } +} diff --git a/src/main/java/ebf/tim/utility/CommonUtil.java b/src/main/java/ebf/tim/utility/CommonUtil.java new file mode 100644 index 0000000000..0e07e8195c --- /dev/null +++ b/src/main/java/ebf/tim/utility/CommonUtil.java @@ -0,0 +1,605 @@ +package ebf.tim.utility; + + +import fexcraft.tmt.slim.Vec3d; +import fexcraft.tmt.slim.Vec3f; +import net.minecraft.block.Block; +import net.minecraft.block.BlockRailBase; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.EntityMinecart; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.ChatComponentText; +import net.minecraft.util.MathHelper; +import net.minecraft.world.IBlockAccess; +import net.minecraft.world.World; +import net.minecraftforge.oredict.OreDictionary; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; +import train.common.Traincraft; +import train.common.api.AbstractTrains; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; + +/** + *

utilities

+ * used for misc utility functions + * + * @author Eternal Blue Flame + * @author Zora No Densha + */ +public class CommonUtil { + /**converts a degrees float to radians*/ + public static final float radianF = (float) Math.PI / 180.0f; + /**converts a radians double to degrees*/ + public static final double degreesD = 180.0d / Math.PI; + public static final float degreesF = (float) (180.0d / Math.PI); + private static List loggedLangChecks = new ArrayList<>(); + + + + /**redirect shorthand that typecasts doubles to ints + * @see #isRailBlockAt(World, int, int, int) */ + public static boolean isRailBlockAt(World world, double x, double y, double z) { + return isRailBlockAt(world,floorDouble(x), floorDouble(y),floorDouble(z)); + } + + public static Block getBlockAt(World world, double x, double y, double z){ + return world.getBlock(floorDouble(x), floorDouble(y),floorDouble(z)); + } + + public static Block getBlockAt(World world, int x, int y, int z){ + return world.getBlock(x,y,z); + } + + public static boolean setBlock(World w, int x, int y, int z, Block b){ + return w.setBlock(x,y,z,b); + } + + public static void setBlockMeta(World w, int x, int y, int z, int meta){ + w.setBlockMetadataWithNotify(x,y,z,meta,2); + w.markBlockRangeForRenderUpdate(x, y, z, x, y, z); + w.notifyBlocksOfNeighborChange(x, y, z, getBlockAt(w,x,y,z)); + w.scheduleBlockUpdate(x, y, z, getBlockAt(w,x,y,z), getBlockAt(w,x,y,z).tickRate(w)); + + w.func_147453_f(x, y, z, getBlockAt(w,x,y,z)); + } + + public static void markBlockForUpdate(World w, int x, int y, int z){ + w.markBlockForUpdate(x,y,z); + } + + public static int getBlockFacing(IBlockAccess w, int x, int y, int z){ + return w.getBlockMetadata(x,y,z); + } + + public static int getRailMeta(IBlockAccess w, EntityMinecart cart, int x, int y, int z){ + return ((BlockRailBase)w.getBlock(x,y,z)).getBasicRailMetadata(w,cart,x,y,z); + } + + public static boolean setBlock(World w, int x, int y, int z, Block b, int meta){ + boolean set =setBlock(w,x,y,z,b); + if(set) { + setBlockMeta(w, x, y, z, meta); + } + return set; + } + + public static float getMaxRailSpeed(World world, BlockRailBase rail, AbstractTrains host, double x, double y, double z){ + return (rail.getRailMaxSpeed(world, host, floorDouble(x), floorDouble(y),floorDouble(z))); + } + + public static int floorDouble(double value){ + return value < (int)value ? ((int)value) - 1 : (int)value; + } + + /** + *

Vanilla Track detection Overrrides

+ * a modified version of vanilla track detection so that way it's more efficient and can support rails from other mods. + */ + public static boolean isRailBlockAt(World world, int x, int y, int z) { + //todo ZnD support, either by jar reference or API update + return (/*world.getTileEntity(x, y, z) instanceof ITrackBase ||*/ world.getBlock(x, y, z) instanceof BlockRailBase); + } + + /** + * sound type does nothing for 1.7.10, + * in later versions it's used to identify what made the sound, like if it's for an entity or a block. + */ + public static void playSound(World world, double xCoord, double yCoord, double zCoord, String file, float volume, float pitch, int soundType){ + world.playSound(xCoord,yCoord,zCoord, file, volume,pitch,false); + } + + public static void playSound(TileEntity tile, String file, float volume, float pitch){ + tile.getWorldObj().playSound(tile.xCoord,tile.yCoord,tile.zCoord, file, volume,pitch,false); + } + + public static void playSound(Entity entity, String file, float volume, float pitch){ + entity.worldObj.playSoundAtEntity(entity, file, volume, pitch); + } + + public static boolean stringContains(String s1, String... s2){ + for(String s3 : s2) { + if (stringContains(s1,s3)){ + return true; + } + } + return false; + } + + public static boolean stringContains(String s1, String s2){ + if (s1 == null || s2 == null) { + return false; + } + return s1.contains(s2); + } + + public static int parseInt(String str, Class host) throws NumberFormatException{ + if (str == null || str.length()==0) { + return 0; + } + + int result = 0; + boolean negative = false; + for (char c : str.toCharArray()) { + switch (c){ + case '-':{negative=true;break;} + case '0':{result = (result * 10);break;} + case '1':{result = (result * 10)+1;break;} + case '2':{result = (result * 10)+2;break;} + case '3':{result = (result * 10)+3;break;} + case '4':{result = (result * 10)+4;break;} + case '5':{result = (result * 10)+5;break;} + case '6':{result = (result * 10)+6;break;} + case '7':{result = (result * 10)+7;break;} + case '8':{result = (result * 10)+8;break;} + case '9':{result = (result * 10)+9;break;} + case ' ':{break;} + default:{throw new NumberFormatException("the string: \"" + str + "\" was not a number, please check " + host.getName());} + } + } + return negative?-result:result; + } + + public static String translate(String text){ + if(Traincraft.proxy.isClient()){ + return ClientUtil.translate(text); + } + return text; + } + + public static String[]multiTranslate(String[] s){ + if(s==null){return null;} + String[] ret = new String[s.length]; + for (int i=0; i listFolders(String path){ + InputStream stream = loadStream(path); + if(stream==null){ + DebugUtil.println("failed to load folder", path); + return new ArrayList<>(); + } + //create a buffered reader for the directory + InputStreamReader reader = new InputStreamReader(stream, StandardCharsets.UTF_8); + BufferedReader buffer = new BufferedReader(reader); + + //build the list of files + List lines = new ArrayList<>(); + String line=""; + while(line !=null){ + try { + line = buffer.readLine(); + if(line!=null) { + lines.add(path + "/" + line); + } + } catch (IOException ignored) {} + } + //close the streams to cleanup + try { + buffer.close(); + reader.close(); + stream.close(); + } catch (IOException ignored) {} + + return lines; + } + + //in some scenarios the file structure seems to change based on whether or not the jar is compiled + public static InputStream loadStream(String file){ + //todo: results may differ with `ClassLoader.getSystemClassLoader().getResourceAsStream` worth trying later + String protocol = Traincraft.instance.getClass().getResource("").getProtocol(); + if(protocol.equals("jar")){ + return Traincraft.instance.getClass().getResourceAsStream("/assets/" + file); + } else if(protocol.equals("file")) { + return Traincraft.instance.getClass().getClassLoader().getResourceAsStream("assets/" + file); + } else { + System.out.println("Unknown way of running project -- not in IDE or jar form!"); + return null; + } +// if(DebugUtil.dev()) { //is dev() reliable? what about deobf but packaged? +// return TrainsInMotion.instance.getClass().getClassLoader().getResourceAsStream("assets/" + file); +// } else { +// return TrainsInMotion.instance.getClass().getResourceAsStream("/resources/" + file); +// } + } + + + //returns file contents as string. returns null if the file does not exist + public static String accessFile(String file) { + InputStream stream = loadStream(file); + + //make a StringWriter and use apache commons to copy the contents of the input stream file + StringWriter reader = new StringWriter(); + try { + if(stream !=null) { + IOUtils.copy(stream, reader); + String str =reader.toString(); + //close the streams to cleanup + try { + reader.close(); + stream.close(); + } catch (IOException ignored) {} + + return str; + } else { + DebugUtil.println(file, " was null"); + return null; + } + } catch (IOException e) { + DebugUtil.println(file, " was not found"); + return null; + } + + } + + + + + public static float calculatePitch(double yBack, double yFront, double distance){ + double yDiff = yFront - yBack; + return (float) ((yDiff / distance) * -CommonUtil.degreesD); + } + + /** + * replacement for system atan2 function. + * uses a lookup list of 1024 float entries (4kb roughly). + * performance is measured at over 15 times more efficient. + * @param x + * @param z + * @return angle in radians + */ + public static float atan2f(double x, double z) { + if (z < 0.0d) { + if (x < 0.0d) { + //0.03225806451 is (1.0D / (ATAN2_SQRT - 1)) + double invDiv = 1.0D / (((-z < -x) ? -x : -z) * 0.03225806451); + return (atan2[(int)(-x * invDiv) * ATAN2_SQRT + (int)(-z * invDiv)] - 3.141592653f); + } else { + double invDiv = 1.0D / (((-z < x) ? x : -z) * 0.03225806451); + return (atan2[(int)(x * invDiv) * ATAN2_SQRT + (int)(-z * invDiv)] - 3.141592653f)*-1; + } + } else { + if (x < 0.0d) { + double invDiv = 1.0D / (((z < -x) ? -x : z) * 0.03225806451); + return (atan2[(int)(-x * invDiv) * ATAN2_SQRT + (int)(z * invDiv)]) * -1; + } + + double invDiv = 1.0D / (((z < x) ? x : z) * 0.03225806451); + return (atan2[(int)(x * invDiv) * ATAN2_SQRT + (int)(z * invDiv)]); + } + } + + public static float atan2degreesf(double x, double y){ + return atan2f(x,y)*57.295779514f; + } + + private static final int ATAN2_SQRT = (int) Math.sqrt(1024);//32 + private static final float[] atan2 = new float[1024]; + static { + for (int i = 0; i < ATAN2_SQRT; i++) { + for (int j = 0; j < ATAN2_SQRT; j++) { + atan2[j * ATAN2_SQRT + i] = (float) Math.atan2((float) j / ATAN2_SQRT, (float) i / ATAN2_SQRT); + } + } + } + + + public static float power(float base, float power){ + return (float)Math.pow(base,power); + } + + public static double getDistanceWithDirection(double fromX, double fromZ, double toX, double toZ, float rotationYaw) { + + double lookX = MathHelper.cos(-rotationYaw * 0.017453292F - (float) Math.PI); + double lookZ = -MathHelper.sin(-rotationYaw * 0.017453292F - (float) Math.PI); + + double vecX=fromX-toX; + double vecZ=fromZ-toZ; + + double dotProduct = vecX * lookX + vecZ * lookZ; + + if (dotProduct < 0) { + // Player 2 is behind Player 1 + return -Math.sqrt(dotProduct); + } else { + return Math.sqrt(dotProduct); + } + } + + /** + *

rotate vector

+ * rotates a given vector based on pitch, yaw, and roll. + * courtesy of Zora No Densha. + * There are version for doubles and floats. + */ + @Deprecated + public static double[] rotatePoint(double[] f, float pitch, float yaw, float roll) { + double cos; + double sin; + double[] xyz = new double[]{f[0],f[1],f[2]}; + //rotate pitch + if (pitch != 0.0F) { + pitch *= radianF; + cos = Math.cos(pitch); + sin = Math.sin(pitch); + + xyz[0] = (f[1] * sin) + (f[0] * cos); + xyz[1] = (f[1] * cos) - (f[0] * sin); + } + //rotate yaw + if (yaw != 0.0F) { + yaw *= radianF; + cos = MathHelper.cos(yaw); + sin = MathHelper.sin(yaw); + + xyz[0] = (f[0] * cos) - (f[2] * sin); + xyz[2] = (f[0] * sin) + (f[2] * cos); + } + //rotate roll + if (roll != 0.0F) { + roll *= radianF; + cos = MathHelper.cos(roll); + sin = MathHelper.sin(roll); + + xyz[1] = (f[2] * cos) - (f[1] * sin); + xyz[2] = (f[2] * sin) + (f[1] * cos); + } + + return xyz; + } + + public static double[] rotatePoint(double f, double pitch, double yaw) { + double cos; + double sin; + double[] xyz = new double[]{f,0,0}; + //rotate pitch + if (pitch != 0.0F) { + pitch *= Math.PI / 180.0f; + cos = Math.cos(pitch); + sin = Math.sin(pitch); + + xyz[0] = (f * cos); + xyz[1] = -(f * sin); + } + //rotate yaw + if (yaw != 0.0F) { + yaw *= Math.PI / 180.0f; + cos = Math.cos(yaw); + sin = Math.sin(yaw); + + xyz[0] = (f * cos); + xyz[2] = (f * sin); + } + + return xyz; + } + + + //private static float cos; + //private static float sin; + //private static float[] xyz = new float[]{0,0,0}; + public static float[] rotatePointF(float x, float y, float z, float pitch, float yaw, float roll) { + float[] xyz = new float[]{x,y,z}; + float sin, cos; + //rotate pitch + if (pitch != 0.0F) { + pitch *= radianF; + cos = MathHelper.cos(pitch); + sin = MathHelper.sin(pitch); + + xyz[0] = (y * sin) + (x * cos); + xyz[1] = (y * cos) - (x * sin); + } + //rotate yaw + if (yaw != 0.0F) { + yaw *= radianF; + cos = MathHelper.cos(yaw); + sin = MathHelper.sin(yaw); + + xyz[0] = (x * cos) - (z * sin); + xyz[2] = (x * sin) + (z * cos); + } + //rotate roll + if (roll != 0.0F) { + roll *= radianF; + cos = MathHelper.cos(roll); + sin = MathHelper.sin(roll); + + xyz[1] = (z * cos) - (y * sin); + xyz[2] = (z * sin) + (y * cos); + } + + return xyz; + } + + public static Vec3f rotatePoint(Vec3f f, float pitch, float yaw, float roll) { + float cos; + float sin; + Vec3f xyz = new Vec3f(f.xCoord, f.yCoord, f.zCoord); + //rotate pitch + if (pitch != 0.0F) { + pitch *= radianF; + cos = MathHelper.cos(pitch); + sin = MathHelper.sin(pitch); + + xyz.xCoord = (f.yCoord * sin) + (f.xCoord * cos); + xyz.yCoord = (f.yCoord * cos) - (f.xCoord * sin); + } + //rotate yaw + if (yaw != 0.0F) { + yaw *= radianF; + cos = MathHelper.cos(yaw); + sin = MathHelper.sin(yaw); + + xyz.xCoord = (f.xCoord * cos) - (f.zCoord * sin); + xyz.zCoord = (f.xCoord * sin) + (f.zCoord * cos); + } + //rotate roll + if (roll != 0.0F) { + roll *= radianF; + cos = MathHelper.cos(roll); + sin = MathHelper.sin(roll); + + xyz.yCoord = (f.zCoord * cos) - (f.yCoord * sin); + xyz.zCoord = (f.zCoord * sin) + (f.yCoord * cos); + } + + return xyz; + } + + @Deprecated //todo: a LOT of calls for this dont use pitch, for efficiency sake there should be a method that doesnt take it + public static Vec3d rotateDistance(double distance, float pitch, float yaw) { + Vec3d xyz = new Vec3d(distance, 0,0); + //rotate pitch + if (pitch != 0.0F) { + pitch *= radianF; + xyz.xCoord = distance * Math.cos(pitch); + xyz.yCoord = distance * Math.sin(pitch); + } + //rotate yaw + if (yaw != 0.0F) { + yaw *= radianF; + xyz.xCoord = (distance * MathHelper.cos(yaw)); + xyz.zCoord = (distance * MathHelper.sin(yaw)); + } + return xyz; + } + + public static void reverseArray(Object[] array) { + if (array != null) { + int i = 0; + for(int j = array.length - 1; j > i; ++i) { + Object tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + --j; + } + } + } + + public static float wrapAngleTo180(double input) { + input %= 360.0d; + + if (input >= 180.0d) { + input -= 360.0d; + } else if (input < -180.0d) { + input += 360.0d; + } + + return (float)input; + } + + + /* + *

Ore Dictionary

+ * we use HashMaps to collect ore directory data because even though it takes longer to collect the data, it's far more efficient to see if an entry exists than a list. + * TODO: maybe have a post-init function to collect the ore directory data? + */ + + + + public static boolean oredictMatch(ItemStack input, String... ore){ + //collect the ore ID's for all relevant ores first + List ores = new ArrayList<>(); + for(String o : ore){ + ores.add(OreDictionary.getOreID(o)); + } + //now itterate the integer inputs for all the oredict entries against all the + for(int id : OreDictionary.getOreIDs(input)){ + for (Integer o : ores) { + if (id == o) { + return true; + } + } + } + return false; + } + + + public static boolean isLog(ItemStack i){ + return oredictMatch(i, "logWood", "woodRubber"); + } + + public static boolean isPlank(ItemStack i){ + return oredictMatch(i, "plankWood", "slabWood"); + } + + public static boolean isCoal(ItemStack i){ + return oredictMatch(i, "coal"); + } + + public static boolean isOre(ItemStack i){ + return oredictMatch(i, "ore"); + } + + + /*

shorthands for lazy bums

*/ + + public static ItemStack DefineStack (Item itm, int size){ + return new ItemStack(itm, size); + } + public static ItemStack DefineStack (Block itm, int size){ + return new ItemStack(Item.getItemFromBlock(itm), size); + } +} diff --git a/src/main/java/ebf/tim/utility/DebugUtil.java b/src/main/java/ebf/tim/utility/DebugUtil.java new file mode 100644 index 0000000000..33d17c0de2 --- /dev/null +++ b/src/main/java/ebf/tim/utility/DebugUtil.java @@ -0,0 +1,140 @@ +package ebf.tim.utility; + +import cpw.mods.fml.common.FMLCommonHandler; +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +/** + * @author Ferdinand + * Fex's debugging util; + */ +public class DebugUtil { + + public static Boolean dev; + + private static Logger LOGGER = LogManager.getLogger("trainsinmotion"); + + + /** + * Replicated method of System.out.println that supports an array of data and only prints in a dev environment. + * @param o + */ + public static void println(Object... o){ + if(dev){ + System.out.println("------------------TiM Debug------------------"); + System.out.println(Thread.currentThread().getStackTrace()[2]);//print what function just called this + for (Object obj : o){ + System.out.println(obj); + } + System.out.println("------------------TiM Debug------------------"); + } + } + + @SideOnly(Side.CLIENT) + public static void printGLError(int glerror){ + if(glerror!=0x0){ + System.out.println("------------------TiM Debug------------------"); + System.out.println(Thread.currentThread().getStackTrace()[2]);//print what function just called this + System.out.println(org.lwjgl.util.glu.GLU.gluErrorString(glerror)); + + printStackTrace(); + System.out.println("------------------TiM Debug------------------"); + } + } + public static void println(Object o){ + if(dev){ + System.out.println("------------------TiM Debug------------------"); + System.out.println(Thread.currentThread().getStackTrace()[2]);//print what function just called this + System.out.println(o); + System.out.println("------------------TiM Debug------------------"); + } + } + + + public static void printStackTrace(){ + if(dev) { + System.out.println("------------------TiM Debug------------------"); + for (StackTraceElement e : Thread.currentThread().getStackTrace()) { + System.out.println(e); + } + System.out.println("------------------TiM Debug------------------"); + } + } + + public static void throwStackTrace(){ + if(dev) { + System.out.println("------------------TiM Debug------------------"); + for (StackTraceElement e : Thread.currentThread().getStackTrace()) { + System.out.println(e); + } + System.out.println("------------------TiM Debug------------------"); + System.exit(-1); + } + } + + /** + * Generic logging method, meant for using an actual minecraft logger; + * @param obj the object to be logged or string + */ + public static void log(Object obj){ + LOGGER.log(Level.WARN, obj); + } + + public static void log(Level level, Object obj){ + LOGGER.log(level, obj); + } + + public static void error(Object obj, Exception e){ + LOGGER.error(obj,e); + } + + public static void error(Object obj){ + LOGGER.error(obj); + } + + //CODE BELLOW COPY/EDITED FROM FCL + + /** + * Alternative to {@link #halt()} or {@link #stop()} which will only work in a developement workspace, nice for debugging. + *
+ * Which also prints the caller classes into console. + *
+ * See also {@link #dev} + */ + public static void exception(int i, String string, boolean halt){ + Exception ex = new Exception(); + for(int j = i; j > 0; j--){ + StackTraceElement elm = ex.getStackTrace()[j]; + log("{" + elm.getClassName() + "#" + elm.getMethodName() + " [LINE: " + elm.getLineNumber() + "]}"); + } + if(string != null){ + log(string); + } + if(dev && halt){ + halt(); + } + } + + /** + * + * @return + */ + public static Side side(){ + return FMLCommonHandler.instance().getSide(); + } + + /** + * Simple method to halt the current Minecraft Instance, "force close". + */ + public static void halt(){ + halt(1); + } + + public static void halt(int errc){ + FMLCommonHandler.instance().exitJava(errc, true); + } + +} \ No newline at end of file diff --git a/src/main/java/ebf/tim/utility/Vec5f.java b/src/main/java/ebf/tim/utility/Vec5f.java new file mode 100644 index 0000000000..7e52fd327b --- /dev/null +++ b/src/main/java/ebf/tim/utility/Vec5f.java @@ -0,0 +1,46 @@ +package ebf.tim.utility; + +import fexcraft.tmt.slim.Vec3f; + +public class Vec5f extends Vec3f { + public float u,v; + + + public Vec5f(double x, double y, double z, float u, float v){ + super(x,y,z); + this.u=u; + this.v=v; + } + + + public Vec5f(Vec5f v){ + super(v.xCoord,v.yCoord,v.zCoord); + this.u=v.u; + this.v=v.v; + } + + public Vec5f(float x, float y, float z, float u, float v){ + super(x,y,z); + this.u=u; + this.v=v; + } + + public void setUV(float u, float v){ + this.u=u; + this.v=v; + } + + public void addUV(float u, float v){ + this.u+=u; + this.v+=v; + } + + public Vec5f crossProduct(Vec5f o){ + return new Vec5f(xCoord*o.xCoord,yCoord*o.yCoord,zCoord*o.zCoord,u*o.u,v*o.v); + } + + + public Vec5f add(Vec5f vec){ + return new Vec5f(xCoord+vec.xCoord,yCoord+vec.yCoord,zCoord+vec.zCoord,u+vec.u,v+vec.v); + } +} diff --git a/src/main/java/ebf/tim/utility/Vec6f.java b/src/main/java/ebf/tim/utility/Vec6f.java new file mode 100644 index 0000000000..175c4c5ebd --- /dev/null +++ b/src/main/java/ebf/tim/utility/Vec6f.java @@ -0,0 +1,46 @@ +package ebf.tim.utility; + +public class Vec6f extends Vec5f { + public float w=0; + + + public Vec6f(double x, double y, double z, float u, float v, float w){ + super(x,y,z,u,v); + this.w=w; + } + + public Vec6f(double x, double y, double z){ + this(x,y,z,0f,0f,0f); + } + + + public Vec6f(Vec5f v){ + super(v.xCoord,v.yCoord,v.zCoord, v.u,v.v); + } + + public Vec6f(float x, float y, float z, float u, float v){ + super(x,y,z,u,v); + } + + public Vec6f setW(float w){ + this.w=w; + return this; + } + + public Vec6f crossProduct(Vec6f o){ + return new Vec6f(xCoord*o.xCoord,yCoord*o.yCoord,zCoord*o.zCoord,u*o.u,v*o.v); + } + + + public Vec6f add(Vec6f vec){ + return new Vec6f(xCoord+vec.xCoord,yCoord+vec.yCoord,zCoord+vec.zCoord,u+vec.u,v+vec.v, w+vec.w); + } + + public float[] toFloatArray(){ + return new float[]{xCoord,yCoord,zCoord,u,v,w}; + } + + public static Vec6f fromFloatArray(float[] f){ + return new Vec6f(f[0],f[1],f[2],f[3],f[4],f[5]); + } +} diff --git a/src/main/java/fexcraft/fcl/common/Static.java b/src/main/java/fexcraft/fcl/common/Static.java new file mode 100644 index 0000000000..4221e5f84e --- /dev/null +++ b/src/main/java/fexcraft/fcl/common/Static.java @@ -0,0 +1,98 @@ +package fexcraft.fcl.common; + +import java.io.InputStream; +import java.util.Random; + +/** + * @author Ferdinand Calo' (FEX___96) + * + * General Class with (mostly) Static content. + */ +public class Static { + + public static boolean mclib = false; + public static boolean devmode = false; + public static boolean server = false; + + public static final float MODELSCALE = 0.0625F; + public static final float PI = 3.14159265358979323846f; + + public static final float sixteenth = 0.0625F; + public static final float eighth = 0.125F; + public static final float quarter = 0.250F; + public static final float half = 0.5F; + + // Radians > Degrees + public static final float rad180 = 3.14159f; + public static final float rad160 = 2.79253f; + public static final float rad120 = 2.0944f; + public static final float rad90 = 1.5708f; + public static final float rad60 = 1.0472f; + public static final float rad45 = 0.785398f; + public static final float rad30 = 0.523599f; + public static final float rad20 = 0.349066f; + public static final float rad12 = 0.20944f; + public static final float rad10 = 0.174533f; + public static final float rad6 = 0.10472f; + public static final float rad5 = 0.0872665f; + public static final float rad1 = 0.0174533f; + + public static final String NULL_UUID_STRING = "00000000-0000-0000-0000-000000000000"; + public static final String DEF1_UUID_STRING = "11111111-1111-1111-1111-111111111111"; + public static final Random random = new Random(); + + public static final String zero(long am){ + StringBuffer buff = new StringBuffer(); + for(long l = 0; l < am; l++) buff.append("0"); + return buff.toString(); + } + + public static final boolean setAsMcLib(boolean bool){ return mclib = bool; } + + public static final boolean setDevmode(boolean bool){ return devmode = bool; } + + public static final boolean setIsServer(boolean bool){ return server = bool; } + + public static final void halt(){ halt(1); } + + public static void halt(int errid){ + if(mclib){ + Static.halt(errid); + } + System.exit(errid); + } + + public static final void stop(){ if(devmode) halt(1); return; } + + public static final boolean dev(){ return devmode; } + + public static boolean isServer(){ + if(mclib){ + Static.isServer(); + } + return server; + } + + public static boolean isClient(){ + if(mclib){ + Static.isClient(); + } + return !server; + } + + public static InputStream getResource(String str){ + if(mclib){ + Static.getResource(str); + } + return Static.class.getClassLoader().getResourceAsStream(str); + } + + public static float toDegrees(float rad){ + return (float)Math.toDegrees(rad); + } + + public static float toRadians(float deg){ + return (float)Math.toRadians(deg); + } + +} \ No newline at end of file diff --git a/src/main/java/fexcraft/fcl/common/lang/ArrayList.java b/src/main/java/fexcraft/fcl/common/lang/ArrayList.java new file mode 100644 index 0000000000..67f1f07f9b --- /dev/null +++ b/src/main/java/fexcraft/fcl/common/lang/ArrayList.java @@ -0,0 +1,38 @@ +package fexcraft.fcl.common.lang; + +import javax.annotation.Nullable; +import java.util.List; + +; + +/** + * @author Ferdinand Calo' (FEX___96) + * + * General ArrayList which will not cause "out of bounds" exceptions, but instead return null or first entry. + * @param + */ +public class ArrayList extends java.util.ArrayList { + + private static final long serialVersionUID = 6551014441630799597L; + + public ArrayList(List list){ + super(list); + } + + public ArrayList(){ + super(); + } + + public ArrayList(T[] arr){ + super(); + for(T e : arr){ + this.add(e); + } + } + + @Override @Nullable + public T get(int i){ + return this.isEmpty() ? null : i > this.size() ? super.get(0) : i < 0 ? null : super.get(i); + } + +} \ No newline at end of file diff --git a/src/main/java/fexcraft/fvtm/RollingStockModel.java b/src/main/java/fexcraft/fvtm/RollingStockModel.java new file mode 100644 index 0000000000..bac228c785 --- /dev/null +++ b/src/main/java/fexcraft/fvtm/RollingStockModel.java @@ -0,0 +1,146 @@ +package fexcraft.fvtm; + +import ebf.tim.utility.DebugUtil; +import fexcraft.tmt.slim.ModelBase; +import fexcraft.tmt.slim.ModelRendererTurbo; +import fexcraft.tmt.slim.Tessellator; +import fexcraft.tmt.slim.TexturedPolygon; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.entity.Entity; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * A compatibility class for "FVTM Scheme/Format" models. + * @Author Eternal BlueFlame + * + * @OriginalAuthor Ferdinand Calo' (FEX___96) + */ + +public class RollingStockModel extends ModelBase { + + public List groups = new ArrayList<>(); + public int textureX, textureY; + public RollingStockModel(){} + + @Override + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5){ + if(init){ + for(TurboList list :groups) { + list.initAllParts(); + } + //for the named list, we sort those into this class to avoid subclassing errors with the animator. + for(TurboList list :groups) { + namedList.addAll(list.namedList); + } + init=false; + } + //this can happen somehow + if(groups==null){ + return; + } + + + if(disableCache) { + for(TurboList list :groups) { + if(list!=null) { + list.render(list.boxList); + } + } + } else if(staticPartMap.get(this.getClass().getName())==null || localGLID==null) { + if(localGLID==null && staticPartMap.get(this.getClass().getName())!=null){ + localGLID = staticPartMap.get(this.getClass().getName()); + return; + } + + staticPartMap.put(this.getClass().getName(), GLAllocation.generateDisplayLists(1)); + GL11.glNewList(staticPartMap.get(this.getClass().getName()), GL11.GL_COMPILE); + localGLID = staticPartMap.get(this.getClass().getName()); + for(TurboList list :groups) { + list.render(list.boxList); + } + GL11.glEndList(); + if(!ModelBase.EnableAnimations) { + for(TurboList list :groups) { + list.boxList = null; + } + } + } else { + if(GL11.glIsList(this.localGLID)) { + GL11.glCallList(this.localGLID); + } else { + staticPartMap.put(this.getClass().getName(), GLAllocation.generateDisplayLists(1)); + GL11.glNewList(staticPartMap.get(this.getClass().getName()), GL11.GL_COMPILE); + localGLID=staticPartMap.get(this.getClass().getName()); + for(TurboList list :groups) { + list.render(list.boxList); + } + GL11.glEndList(); + } + } + + if(namedList ==null){return;} + for(ModelRendererTurbo part : namedList) { + //for animations to work we have to limit the displaylist cache to ONLY the geometry, and then + // the position and offsets must be done manually every frame. + if (!part.showModel) { + continue; + } + GL11.glPushMatrix(); + if (part.ignoresLighting) { + Minecraft.getMinecraft().entityRenderer.disableLightmap(1D); + } + GL11.glTranslatef(part.rotationPointX * 0.0625F, part.rotationPointY * 0.0625F, part.rotationPointZ * 0.0625F); + GL11.glRotatef(part.rotateAngleY, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(part.rotateAngleZ, 0.0F, 0.0F, 1.0F); + GL11.glRotatef(part.rotateAngleX, 1.0F, 0.0F, 0.0F); + if (part.glID!=null && GL11.glIsList(part.glID)) { + GL11.glCallList(part.glID); + } else { + part.glID = GLAllocation.generateDisplayLists(1); + GL11.glNewList(part.glID, GL11.GL_COMPILE); + for (TexturedPolygon poly : part.faces) { + Tessellator.getInstance().drawTexturedVertsWithNormal(poly, 0.0625F); + } + GL11.glEndList(); + } + + GL11.glTranslatef(-part.rotationPointX * 0.0625F, -part.rotationPointY * 0.0625F, -part.rotationPointZ * 0.0625F); + if (part.ignoresLighting) { + Minecraft.getMinecraft().entityRenderer.enableLightmap(1D); + } + GL11.glPopMatrix(); + + + } + } + + @Override + public List getnamedParts(){ + if(init){ + for(TurboList list :groups) { + list.initAllParts(); + } + //for the named list, we sort those into this class to avoid subclassing errors with the animator. + for(TurboList list :groups) { + namedList.addAll(list.namedList); + } + init=false; + } + return namedList; + } + + public TurboList get(String s){ + for(TurboList t : groups){ + if(t.boxname.equals(s)){ + return t; + } + } + return null; + } + +} diff --git a/src/main/java/fexcraft/fvtm/TurboList.java b/src/main/java/fexcraft/fvtm/TurboList.java new file mode 100644 index 0000000000..cee80ae82e --- /dev/null +++ b/src/main/java/fexcraft/fvtm/TurboList.java @@ -0,0 +1,52 @@ +package fexcraft.fvtm; + +import fexcraft.tmt.slim.ModelBase; +import fexcraft.tmt.slim.ModelRendererTurbo; +import org.lwjgl.opengl.GL11; + +/** + * A compatibility class for "FVTM Scheme/Format" or "FMT" models. + * @Author Eternal BlueFlame + * + * @OriginalAuthor Ferdinand Calo' (FEX___96) + */ +public class TurboList extends ModelBase { + + public String boxname; + public TurboList(String name){ + boxname=name; + } + + public boolean add(ModelRendererTurbo t){ + super.addPart(t); + return true; + } + + @Override + public void flip(ModelRendererTurbo[] model) { + if(model==null){return;} + for(ModelRendererTurbo mod : model){ + mod.rotateAngleY = -mod.rotateAngleY; + mod.rotateAngleZ = -mod.rotateAngleZ; + } + } + + @Override + public void render(){ + for(ModelRendererTurbo sub : boxList){ + if(sub!=null) { + GL11.glPushMatrix(); + sub.render(); + GL11.glPopMatrix(); + } + } + for(ModelRendererTurbo sub : namedList){ + if(sub!=null) { + GL11.glPushMatrix(); + sub.render(); + GL11.glPopMatrix(); + } + } + } + +} diff --git a/src/main/java/fexcraft/tmt/slim/BoxBuilder.java b/src/main/java/fexcraft/tmt/slim/BoxBuilder.java new file mode 100644 index 0000000000..9430ea2128 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/BoxBuilder.java @@ -0,0 +1,233 @@ +package fexcraft.tmt.slim; + +import java.util.ArrayList; +import java.util.List; + +/** + * Reverse engineered for TMT slim by EternalBlueFlame + * @author Ferdinand Calo' (FEX___96) + */ +public class BoxBuilder { + + private static final Vec3f NULLVEC = new Vec3f(0, 0, 0); + private final ModelRendererTurbo host; + private float x, y, z, expansion, w, h, d; + private boolean[] invisible = new boolean[]{false,false,false,false,false,false}; + private float[][] uv = new float[6][]; + private boolean[] detached = new boolean[6]; + private Vec3f[] corners = new Vec3f[]{NULLVEC,NULLVEC,NULLVEC,NULLVEC,NULLVEC,NULLVEC,NULLVEC,NULLVEC}; + + public BoxBuilder(){ + this(null); + } + + public BoxBuilder(ModelRendererTurbo root){ + this.host = root == null ? new ModelRendererTurbo("") : root; + } + + public BoxBuilder setOffset(float x, float y, float z){ + this.x = x; this.y = y; this.z = z; + return this; + } + + public BoxBuilder setSize(float w, float h, float d){ + this.w = w; this.h = h; this.d = d; + return this; + } + + public BoxBuilder setExpansion(float exp){ + this.expansion = exp; + return this; + } + + public BoxBuilder removePolygon(int index){ + invisible[index] = true; + return this; + } + + public BoxBuilder removePolygons(int... poly_indices){ + for(int index : poly_indices){ + invisible[index] = true; + } + return this; + } + + public BoxBuilder removePolygons(boolean... sides){ + for(int index = 0; index < 6; index++){ + if(sides.length >= (index + 1) && sides[index]) invisible[index] = true; + } + return this; + } + + public BoxBuilder setPolygonUV(int poly_index, float[] uv){ + this.uv[poly_index] = uv; + return this; + } + + public BoxBuilder setPolygonUVs(int[] poly_indices, float[][] uvs){ + for(int i = 0; i < poly_indices.length; i++){ + setPolygonUV(poly_indices[i], uvs[i]); + } + return this; + } + + public BoxBuilder setPolygonUVs(float[][] uvs){ + for(int index = 0; index < 6; index++){ + if(index >= uvs.length) break; + setPolygonUV(index, uvs[index]); + } + return this; + } + + public BoxBuilder setDetachedUV(int... indices){ + for(int index : indices){ + detached[index] = true; + } + return this; + } + + public BoxBuilder setDetachedUV(boolean... bools){ + for(int index = 0; index < 6; index++){ + if(index >= bools.length) break; + setDetachedUV(index); + } + return this; + } + + private float detached(int i, float value){ + return invisible[i] || detached[i]?0:value; + } + + public BoxBuilder setCorner(int index, Vec3f corner){ + corners[index] = corner==null?NULLVEC:corner; + return this; + } + + public BoxBuilder setCorner(int index, float x, float y, float z){ + corners[index] = new Vec3f(x, y, z); + return this; + } + + + public BoxBuilder setCorners(Vec3f cor0, Vec3f cor1, Vec3f cor2, Vec3f cor3, Vec3f cor4, Vec3f cor5, Vec3f cor6, Vec3f cor7){ + corners[0] = cor0==null?NULLVEC:cor0; + corners[1] = cor1==null?NULLVEC:cor1; + corners[2] = cor2==null?NULLVEC:cor2; + corners[3] = cor3==null?NULLVEC:cor3; + corners[4] = cor4==null?NULLVEC:cor4; + corners[5] = cor5==null?NULLVEC:cor5; + corners[6] = cor6==null?NULLVEC:cor6; + corners[7] = cor7==null?NULLVEC:cor7; + return this; + } + + public BoxBuilder setCorners(float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float x5, float y5, float z5, float x6, float y6, float z6, float x7, float y7, float z7){ + corners[0] = new Vec3f(x0, y0, z0); + corners[1] = new Vec3f(x1, y1, z1); + corners[2] = new Vec3f(x2, y2, z2); + corners[3] = new Vec3f(x3, y3, z3); + corners[4] = new Vec3f(x4, y4, z4); + corners[5] = new Vec3f(x5, y5, z5); + corners[6] = new Vec3f(x6, y6, z6); + corners[7] = new Vec3f(x7, y7, z7); + return this; + } + + public ModelRendererTurbo build(){ + if(w == 0) w = 0.01F; if(h == 0) h = 0.01F; if(d == 0) d = 0.01F; + float xw = x + w, yh = y + h, zd = z + d; + xw += expansion; yh += expansion; zd += expansion; + if(host.mirror){ float fl = xw; xw = x; x = fl; } + List poly = new ArrayList<>(); + TexturedVertex tv0 = new TexturedVertex(x - corners[0].xCoord, y - corners[0].yCoord, z - corners[0].zCoord, 0.0F, 0.0F); + TexturedVertex tv1 = new TexturedVertex(xw + corners[1].xCoord, y - corners[1].yCoord, z - corners[1].zCoord, 0.0F, 8.0F); + TexturedVertex tv2 = new TexturedVertex(xw + corners[5].xCoord, yh + corners[5].yCoord, z - corners[5].zCoord, 8.0F, 8.0F); + TexturedVertex tv3 = new TexturedVertex(x - corners[4].xCoord, yh + corners[4].yCoord, z - corners[4].zCoord, 8.0F, 0.0F); + TexturedVertex tv4 = new TexturedVertex(x - corners[3].xCoord, y - corners[3].yCoord, zd + corners[3].zCoord, 0.0F, 0.0F); + TexturedVertex tv5 = new TexturedVertex(xw + corners[2].xCoord, y - corners[2].yCoord, zd + corners[2].zCoord, 0.0F, 8.0F); + TexturedVertex tv6 = new TexturedVertex(xw + corners[6].xCoord, yh + corners[6].yCoord, zd + corners[6].zCoord, 8.0F, 8.0F); + TexturedVertex tv7 = new TexturedVertex(x - corners[7].xCoord, yh + corners[7].yCoord, zd + corners[7].zCoord, 8.0F, 0.0F); + if(w % 1 != 0){ + w = w < 1 ? 1 : (int)w + 1; + } + if(h % 1 != 0){ + h = h < 1 ? 1 : (int)h + 1; + } + if(d % 1 != 0){ + d = d < 1 ? 1 : (int)d + 1; + } + + float yp = (invisible[2] || detached[2]) && invisible[3] || detached[3] ? 0 : d; + if(!invisible[0]){ + poly.add(genPolygonWithUV(0, new TexturedVertex[] { tv5, tv1, tv2, tv6 }, host.textureOffsetX, host.textureOffsetY, detached(1,d) + detached(4,w), yp, d, h)); + } + if(!invisible[1]){ + poly.add(genPolygonWithUV(1, new TexturedVertex[] { tv0, tv4, tv7, tv3 }, host.textureOffsetX, host.textureOffsetY, 0, yp, d, h)); + } + if(!invisible[2]){ + poly.add(genPolygonWithUV(2, new TexturedVertex[] { tv5, tv4, tv0, tv1 }, host.textureOffsetX, host.textureOffsetY, detached(1,d), 0, w, d)); + } + if(!invisible[3]){ + poly.add(genPolygonWithUV(3, new TexturedVertex[] { tv2, tv3, tv7, tv6 }, host.textureOffsetX, host.textureOffsetY, detached(1,d) + detached(2,w), 0, w, d)); + } + if(!invisible[4]){ + poly.add(genPolygonWithUV(4, new TexturedVertex[] { tv1, tv0, tv3, tv2 }, host.textureOffsetX, host.textureOffsetY, detached(1,d), yp, w, h)); + } + if(!invisible[5]){ + poly.add(genPolygonWithUV(5, new TexturedVertex[] { tv4, tv5, tv6, tv7 }, host.textureOffsetX, host.textureOffsetY, detached(1,d) + detached(4,w) + detached(0,d), yp, w, h)); + } + if(host.mirror){ + for (TexturedPolygon aPoly : poly) { + if (aPoly != null){ + aPoly.flipFace(); + } + } + } + host.faces.addAll(poly); + return host; + } + + private TexturedPolygon genPolygonWithUV(int index, TexturedVertex[] vertices, float texX, float texY, float x, float y, float x2, float y2){ + if(detached[index]){ + texX = 0; + texY = 0; + } + float texX1,texX2,texY1,texY2; + if(uv[index] == null){ + texX1 = (texX + x) / host.textureWidth; + texX2 = (texX + x + x2) / host.textureWidth; + texY1 = (texY + y) / host.textureHeight; + texY2 = (texY + y + y2) / host.textureHeight; + } + else if(uv[index].length == 2){ + texX1 = (texX + uv[index][0]) / host.textureWidth; + texX2 = (texX + uv[index][0] + x2) / host.textureWidth; + texY1 = (texY + uv[index][1]) / host.textureHeight; + texY2 = (texY + uv[index][1] + y2) / host.textureHeight; + } + else if(uv[index].length == 4){ + texX1 = (texX + uv[index][0]) / host.textureWidth; + texX2 = (texX + uv[index][2]) / host.textureWidth; + texY1 = (texY + uv[index][1]) / host.textureHeight; + texY2 = (texY + uv[index][3]) / host.textureHeight; + } + else if(uv[index].length == 8){//8 is weird, this needs to be overly exact. + vertices[0].setUV((texX + uv[index][0]) / host.textureWidth, (texY + uv[index][1]) / host.textureHeight); + vertices[1].setUV((texX + uv[index][2]) / host.textureWidth, (texY + uv[index][3]) / host.textureHeight); + vertices[2].setUV((texX + uv[index][4]) / host.textureWidth, (texY + uv[index][5]) / host.textureHeight); + vertices[3].setUV((texX + uv[index][6]) / host.textureWidth, (texY + uv[index][7]) / host.textureHeight); + return new TexturedPolygon(vertices); + } + else { + texX1 = (texX + x) / host.textureWidth; + texX2 = (texX + x + x2) / host.textureWidth; + texY1 = (texY + y) / host.textureHeight; + texY2 = (texY + y + y2) / host.textureHeight; + } + vertices[0].setUV(texX2,texY1); + vertices[1].setUV(texX1, texY1); + vertices[2].setUV(texX1, texY2); + vertices[3].setUV(texX2, texY2); + return new TexturedPolygon(vertices); + } +} diff --git a/src/main/java/fexcraft/tmt/slim/Coord2D.java b/src/main/java/fexcraft/tmt/slim/Coord2D.java new file mode 100644 index 0000000000..5c7efd5cd8 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/Coord2D.java @@ -0,0 +1,30 @@ +package fexcraft.tmt.slim; + +/** + * This class represents a coordinate space and its UV coordinates. This allows for + * easier flat shape planning. + * @author GaryCXJk + * + */ +public class Coord2D { + + public float xCoord; + public float yCoord; + public int uCoord; + public int vCoord; + + public Coord2D(float x, float y){ + xCoord = x; + yCoord = y; + uCoord = (int)Math.floor(x); + vCoord = (int)Math.floor(y); + } + + + public Coord2D(float x, float y, int u, int v){ + this(x, y); + uCoord = u; + vCoord = v; + } + +} diff --git a/src/main/java/fexcraft/tmt/slim/CylinderBuilder.java b/src/main/java/fexcraft/tmt/slim/CylinderBuilder.java new file mode 100644 index 0000000000..8ebb699163 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/CylinderBuilder.java @@ -0,0 +1,279 @@ +package fexcraft.tmt.slim; + +import java.util.ArrayList; + +import static fexcraft.tmt.slim.ModelRendererTurbo.*; + +public class CylinderBuilder { + + private ModelRendererTurbo root; + private float x, y, z, radius, radius2, radius3, radius4, length, base_scale, top_scale; + private int segments, seglimit, direction, texDiameterW, texDiameterH, texHeight; + private Vec3f topoff = new Vec3f(); + private boolean[] togglesides = new boolean[]{false,false,false,false}; + private Vec3f toprot; + // + private boolean radialtexture = false; + private float seg_width, seg_height; + + public CylinderBuilder(ModelRendererTurbo root){ + this.root = root == null ? new ModelRendererTurbo("") : root; + } + + public CylinderBuilder setPosition(float x, float y, float z){ + this.x = x; this.y = y; this.z = z; return this; + } + + public CylinderBuilder setRadius(float first, float second){ + this.radius = first; this.radius2 = second; texDiameterW = (int)Math.floor(radius * 2F); texDiameterH = (int)Math.floor(radius * 2F); return this; + } + + public CylinderBuilder setRadius(float first_s, float first_c, float second_s, float second_c){ + this.radius3 = first_c; this.radius4 = second_c; + return setRadius(first_s, second_s); + } + + /** Use AFTER `setRadius`, else values will get overriden. */ + public CylinderBuilder setTextureDiameter(int width, int height){ + texDiameterW = width; texDiameterH = height; return this; + } + + public CylinderBuilder setLength(float length){ + this.length = length; texHeight = (int)Math.floor(length); return this; + } + + /** Use AFTER `setLength`, else value will get overriden. */ + public CylinderBuilder setTextureHeight(int height){ + texHeight = height; return this; + } + + public CylinderBuilder setTopOffset(float x, float y, float z){ + topoff = new Vec3f(x, y, z); return this; + } + + public CylinderBuilder setTopOffset(Vec3f vec){ + topoff = vec; return this; + } + + public CylinderBuilder setSidesVisible(boolean[] arr){ + this.togglesides = arr; return this; + } + + public CylinderBuilder setSidesVisible(boolean base, boolean top, boolean outer, boolean inner){ + this.togglesides = new boolean[]{ base, top, outer, inner }; return this; + } + + /** Currently no support for hollow-less cylinders to be segmented. */ + public CylinderBuilder setSegments(int amount, int limit){ + this.segments = amount; this.seglimit = limit; return this; + } + + public CylinderBuilder setScale(float base, float top){ + this.base_scale = base; this.top_scale = top; return this; + } + + /** Currently no support for hollow-less cylinders to be radial-textured. */ + public CylinderBuilder setRadialTexture(float seg_width, float seg_height){ + if(seg_width==0 && seg_height==0){ + return this; + } + radialtexture = true; this.seg_width = seg_width; this.seg_height = seg_height; return this; + } + + public CylinderBuilder setDirection(int dir){ + this.direction = dir; return this; + } + + public CylinderBuilder setTopRotation(float x, float y, float z){ + toprot = new Vec3f(x,y,z); + return this; + } + + public CylinderBuilder setTopRotation(Vec3f vec){ + return setTopRotation(vec.xCoord, vec.yCoord, vec.zCoord); + } + + public CylinderBuilder removePolygon(int index){ + if(index >= 0 && index < 4){ + togglesides[index] = true; + } + return this; + } + + public CylinderBuilder removePolygons(int... poly_indices){ + for(int index : poly_indices){ + if(index >= 0 && index < 4){ + togglesides[index] = true; + } + } + return this; + } + + public CylinderBuilder removePolygons(boolean... sides){ + for(int index = 0; index < 4; index++){ + if(sides.length >= (index + 1) && sides[index]){ + togglesides[index] = true; + } + } + return this; + } + + public ModelRendererTurbo build(){ + if(radius3 == 0f) radius3 = radius; + if(radius4 == 0f) radius4 = radius2; + if(radius2 == 0f && toprot == null && radius3 == radius){ + return root.addCylinder(x, y, z, radius, length, segments, base_scale, top_scale, direction, texDiameterW, texDiameterH, texHeight, topoff); + } + if(radius < 1){ texDiameterW = 2; texDiameterH = 2; } if(length < 1){ texHeight = 2; } + // + boolean dirTop = (direction == MR_TOP || direction == MR_BOTTOM); + boolean dirSide = (direction == MR_RIGHT || direction == MR_LEFT); + boolean dirFront = (direction == MR_FRONT || direction == MR_BACK); + boolean dirMirror = (direction == MR_LEFT || direction == MR_BOTTOM || direction == MR_BACK); + if(base_scale == 0) base_scale = 1f; if(top_scale == 0) top_scale = 1f; + if(segments < 3) segments = 3; if(seglimit <= 0) seglimit = segments; boolean segl = seglimit < segments; + ArrayList polis = new ArrayList<>(); + //Vertex + float xLength = (dirSide ? length : 0), yLength = (dirTop ? length : 0), zLength = (dirFront ? length : 0); + float xStart = (dirMirror ? x + xLength : x); + float yStart = (dirMirror ? y + yLength : y); + float zStart = (dirMirror ? z + zLength : z); + float xEnd = (!dirMirror ? x + xLength : x) + (topoff == null ? 0 : topoff.xCoord); + float yEnd = (!dirMirror ? y + yLength : y) + (topoff == null ? 0 : topoff.yCoord); + float zEnd = (!dirMirror ? z + zLength : z) + (topoff == null ? 0 : topoff.zCoord); + float xCur = xStart, yCur = yStart, zCur = zStart, sCur = base_scale; + //Texture + float uScale = 1.0F / root.textureWidth, vScale = 1.0F / root.textureHeight; + float uOffset = uScale / 20.0F, vOffset = vScale / 20.0F; + float uCircle = texDiameterW * uScale; + float vCircle = texDiameterH * vScale; + float uCircle2 = ((int)Math.floor(radius2 * 2F)) * uScale; + float vCircle2 = ((int)Math.floor(radius2 * 2F)) * vScale; + float uWidth = (uCircle * 2F - uOffset * 2F) / segments; + float vHeight = texHeight * vScale - uOffset * 2f; + float uStart = root.textureOffsetX * uScale, vStart = root.textureOffsetY * vScale; + //Temporary Arrays + ArrayList verts0 = new ArrayList<>(), verts1 = new ArrayList<>(), + verts2 = new ArrayList<>(), verts3 = new ArrayList<>(); + float xSize,ySize,zSize,xPlace,yPlace,zPlace; + for(int repeat = 0; repeat < 2; repeat++){//top/base faces + for(int index = 0; index < segments; index++){ + xSize = (float)((root.mirror ^ dirMirror ? -1 : 1) * Math.sin((ModelRendererTurbo.pi / segments) * index * 2F + ModelRendererTurbo.pi) * radius * sCur); + zSize = (float)(-Math.cos((ModelRendererTurbo.pi / segments) * index * 2F + ModelRendererTurbo.pi) * radius3 * sCur); + xPlace = xCur + (!dirSide ? xSize : 0); + yPlace = yCur + (!dirTop ? zSize : 0); + zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); + verts0.add(new TexturedVertex(xPlace, yPlace, zPlace, 0, 0)); + if(index == segments - 1){ + verts0.add(new TexturedVertex(verts0.get(0))); + } + // + xSize = (float)((root.mirror ^ dirMirror ? -1 : 1) * Math.sin((ModelRendererTurbo.pi / segments) * index * 2F + ModelRendererTurbo.pi) * radius2 * sCur); + zSize = (float)(-Math.cos((ModelRendererTurbo.pi / segments) * index * 2F + ModelRendererTurbo.pi) * radius4 * sCur); + xPlace = xCur + (!dirSide ? xSize : 0); + yPlace = yCur + (!dirTop ? zSize : 0); + zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); + verts1.add(new TexturedVertex(xPlace, yPlace, zPlace, 0, 0)); + if(index == segments - 1){ + verts1.add(new TexturedVertex(verts1.get(0))); + } + } + if(repeat == 0){ + verts2.addAll(verts0); + verts2.addAll(verts1); + } else{ + verts3.addAll(verts0); + verts3.addAll(verts1); + } + float mul = radialtexture ? repeat == 0 ? 0 : seg_height : repeat == 0 ? 0.5f : 1.5f; + if((repeat == 0 && !togglesides[0]) || (repeat == 1 && !togglesides[1])){ + for(int i = 0; i < verts0.size(); i++){ + if(i >= (verts0.size() - 1) || i >= seglimit){ + if(repeat != 0 && toprot != null){ + verts0.get(i).vector3F = toprot.getRelativeVector(verts0.get(i).vector3F); + verts1.get(i).vector3F = toprot.getRelativeVector(verts1.get(i).vector3F); + } + break; + } + TexturedVertex[] arr = new TexturedVertex[4]; + if(!radialtexture){ + xSize = (float)(Math.sin((ModelRendererTurbo.pi / segments) * i * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * uCircle - 2F * uOffset)); + ySize = (float)(Math.cos((ModelRendererTurbo.pi / segments) * i * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * vCircle - 2F * vOffset)); + arr[0] = verts0.get(i).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + // + xSize = (float)(Math.sin((ModelRendererTurbo.pi / segments) * i * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * uCircle2 - 2F * uOffset)); + ySize = (float)(Math.cos((ModelRendererTurbo.pi / segments) * i * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * vCircle2 - 2F * vOffset)); + arr[1] = verts1.get(i).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + // + xSize = (float)(Math.sin((ModelRendererTurbo.pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * uCircle2 - 2F * uOffset)); + ySize = (float)(Math.cos((ModelRendererTurbo.pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * vCircle2 - 2F * vOffset)); + arr[2] = verts1.get(i + 1).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + // + xSize = (float)(Math.sin((ModelRendererTurbo.pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * uCircle - 2F * uOffset)); + ySize = (float)(Math.cos((ModelRendererTurbo.pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : ModelRendererTurbo.pi)) * (0.5F * vCircle - 2F * vOffset)); + arr[3] = verts0.get(i + 1).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + } else { + float diff = (radius - radius2) * uScale / 4; + arr[0] = verts0.get(i).setTexturePosition(uStart + (i * seg_width) * uScale, vStart + (mul * vScale)); + arr[1] = verts1.get(i).setTexturePosition(uStart + (i * seg_width) * uScale + diff, vStart + ((seg_height + mul) * vScale)); + arr[2] = verts1.get(i + 1).setTexturePosition(uStart + ((i + 1) * seg_width) * uScale - diff, vStart + ((seg_height + mul) * vScale)); + arr[3] = verts0.get(i + 1).setTexturePosition(uStart + ((i + 1) * seg_width) * uScale, vStart + (mul * vScale)); + } + if(repeat != 0 && toprot != null){ + arr[0].vector3F = verts0.get(i).vector3F = toprot.getRelativeVector(arr[0].vector3F); + arr[1].vector3F = verts1.get(i).vector3F = toprot.getRelativeVector(arr[1].vector3F); + arr[2].vector3F = /*verts1.get(i + 1).vector3F =*/ toprot.getRelativeVector(arr[2].vector3F); + arr[3].vector3F = /*verts0.get(i + 1).vector3F =*/ toprot.getRelativeVector(arr[3].vector3F); + } + polis.add(new TexturedPolygon(arr)); + if((repeat == 0) != dirFront) { + polis.get(polis.size() - 1 ).flipFace(); + } + } + } + verts0.clear(); verts1.clear(); xCur = xEnd; yCur = yEnd; zCur = zEnd; sCur = top_scale; + } + int halfv2 = verts2.size() / 2; + if(radialtexture){ vCircle = (seg_height + seg_height) * vScale; } + for(int i = 0; i < halfv2; i++){ + if(i >= seglimit && segl){ + TexturedVertex[] arr = new TexturedVertex[4]; float xpos = uStart + uOffset + (uCircle * 2f); + arr[0] = verts2.get(0).setTexturePosition(xpos, vStart + vOffset + vCircle); + arr[1] = verts3.get(0).setTexturePosition(xpos, vStart + vOffset + vCircle + vHeight); + arr[2] = verts3.get(halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle + vHeight); + arr[3] = verts2.get(halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle); + polis.add(new TexturedPolygon(arr)); + if(!dirFront) polis.get(polis.size() - 1 ).flipFace(); + arr = new TexturedVertex[4]; + arr[0] = verts2.get(seglimit).setTexturePosition(xpos, vStart + vOffset + vCircle + vHeight); + arr[1] = verts3.get(seglimit).setTexturePosition(xpos, vStart + vOffset + vCircle + vHeight + vHeight); + arr[2] = verts3.get(seglimit + halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle + vHeight + vHeight); + arr[3] = verts2.get(seglimit + halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle + vHeight); + polis.add(new TexturedPolygon(arr)); + if(dirFront) polis.get(polis.size() - 1 ).flipFace(); + break; + } + if(i >= (halfv2 - 1)) break; + TexturedVertex[] arr = new TexturedVertex[4]; + if(!togglesides[2]){ + arr[0] = verts2.get(i + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle); + arr[1] = verts3.get(i + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle + vHeight); + arr[2] = verts3.get(i + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle + vHeight); + arr[3] = verts2.get(i + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle); + polis.add(new TexturedPolygon(arr)); + if(dirFront) polis.get(polis.size() - 1 ).flipFace(); + } + if(!togglesides[3]){ + arr = new TexturedVertex[4]; + arr[0] = verts2.get(i + halfv2 + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle + vHeight); + arr[1] = verts3.get(i + halfv2 + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle + vHeight + vHeight); + arr[2] = verts3.get(i + halfv2 + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle + vHeight + vHeight); + arr[3] = verts2.get(i + halfv2 + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle + vHeight); + polis.add(new TexturedPolygon(arr)); + if(!dirFront) polis.get(polis.size() - 1 ).flipFace(); + } + } + root.faces.addAll(polis); + return root; + } +} \ No newline at end of file diff --git a/src/main/java/fexcraft/tmt/slim/JsonToTMT.java b/src/main/java/fexcraft/tmt/slim/JsonToTMT.java new file mode 100644 index 0000000000..6f00903fca --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/JsonToTMT.java @@ -0,0 +1,149 @@ +package fexcraft.tmt.slim; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + + +/** +* Tool to parse `ModelRendererTurbo` objects from JSON. +* @Author Ferdinand Calo' (FEX___96) +*/ +public class JsonToTMT { + + //def + public static final float def = 0f; + public static final int idef = 0; + //common + public static final String[] format = new String[]{"format", "form", "f"};//1.1f + public static final String[] width = new String[]{"width", "wid", "w"}; + public static final String[] height = new String[]{"height", "hgt", "h"}; + public static final String[] depth = new String[]{"depth", "dep", "d"}; + public static final String[] offx = new String[]{"offset_x", "off_x", "offx", "ox"}; + public static final String[] offy = new String[]{"offset_y", "off_y", "offy", "oy"}; + public static final String[] offz = new String[]{"offset_z", "off_z", "offz", "oz"}; + public static final String[] expansion = new String[]{"expansion", "exp", "e"}; + public static final String[] scale = new String[]{"scale", "s"}; + public static final String[] texturex = new String[]{"texture_x", "texturex", "tex_x", "tx"}; + public static final String[] texturey = new String[]{"texture_y", "texturey", "tex_y", "ty"}; + // + public static final String[] posx = new String[]{"rotation_point_x", "pos_x", "posx", "px", "x"}; + public static final String[] posy = new String[]{"rotation_point_y", "pos_y", "posy", "py", "y"}; + public static final String[] posz = new String[]{"rotation_point_z", "pos_z", "posz", "pz", "z"}; + public static final String[] rotx = new String[]{"rotation_angle_x", "rotangle_x", "rotanglex", "rot_x", "rx"}; + public static final String[] roty = new String[]{"rotation_angle_y", "rotangle_y", "rotangley", "rot_y", "ry"}; + public static final String[] rotz = new String[]{"rotation_angle_z", "rotangle_z", "rotanglez", "rot_z", "rz"}; + //settings + public static final String[] oldrot = new String[]{"old_ration", "old_rotation_order", "oro"}; + public static final String[] mirror = new String[]{"mirror", "mir", "m"}; + public static final String[] flip = new String[]{"flip", "fl", "usd"}; + //cyl + public static final String[] radius = new String[]{"radius", "rad", "r"}; + public static final String[] length = new String[]{"length", "len", "l"}; + public static final String[] segments = new String[]{"segments", "seg", "sg"}; + public static final String[] basescale = new String[]{"base_scale", "basescale", "bs"}; + public static final String[] topscale = new String[]{"top_scale", "topscale", "ts"}; + public static final String[] direction = new String[]{"direction", "dir", "facing"}; + + public final static ModelRendererTurbo parse(ModelBase base, JsonObject obj, int tx, int ty){ + ModelRendererTurbo model = new ModelRendererTurbo(base, get(texturex, obj, idef), get(texturey, obj, idef), tx, ty); + // + float x = get(offx, obj, def); + float y = get(offy, obj, def); + float z = get(offz, obj, def); + int w = get(width, obj, idef); + int h = get(height, obj, idef); + int d = get(depth, obj, idef); + // + switch(obj.get("type").getAsString()){ + case "box": case "cube": case "b": { + model.addBox(x, y, z, w, h, d, get(expansion, obj, def)); + break; + } + case "shapebox": case "sbox": case "sb": { + model.addShapeBox(x, y, z, w, h, d, get(scale, obj, def), + get("x0", obj, def), get("y0", obj, def), get("z0", obj, def), + get("x1", obj, def), get("y1", obj, def), get("z1", obj, def), + get("x2", obj, def), get("y2", obj, def), get("z2", obj, def), + get("x3", obj, def), get("y3", obj, def), get("z3", obj, def), + get("x4", obj, def), get("y4", obj, def), get("z4", obj, def), + get("x5", obj, def), get("y5", obj, def), get("z5", obj, def), + get("x6", obj, def), get("y6", obj, def), get("z6", obj, def), + get("x7", obj, def), get("y7", obj, def), get("z7", obj, def) + ); + break; + } + case "cylinder": case "cyl": case "c": { + model.addCylinder(x, y, z, get(radius, obj, 1f), get(length, obj, 1f), get(segments, obj, 16), get(basescale, obj, 1f), get(topscale, obj, 1f), get(direction, obj, 4)); + break; + } + case "cone": case "cn": { + model.addCone(x, y, z, get(radius, obj, 1f), get(length, obj, 1f), get(segments, obj, 12), get(basescale, obj, 1f), get(direction, obj, 4)); + break; + } + } + /* import unavailable: net.fexcraft.mod.lib.util.json.JsonUtil; + model.rotorder = JsonUtil.getIfExists(obj, oldrot, model.rotorder); + model.mirror = JsonUtil.getIfExists(obj, mirror, false); + model.flip = JsonUtil.getIfExists(obj, flip, false); + */ + model.rotateAngleX = get(rotx, obj, def); + model.rotateAngleY = get(roty, obj, def); + model.rotateAngleZ = get(rotz, obj, def); + // + model.setRotationPoint(get(posx, obj, def), get(posy, obj, def), get(posz, obj, def)); + return model; + } + + public final static ModelRendererTurbo[] parse(ModelBase base, JsonArray array, int tx, int ty){ + if(array != null){ + ModelRendererTurbo[] model = new ModelRendererTurbo[array.size()]; + for(int i = 0; i < array.size(); i++){ + model[i] = parse(base, array.get(i).getAsJsonObject(), tx, ty); + } + return model; + } + return new ModelRendererTurbo[0]; + } + + public final static ModelRendererTurbo[] parse(ModelBase base, String string, JsonObject object, int tx, int ty){ + if(base == null){ + /*unavailable import, could be easily replaced with generic debugger later on + if(Static.dev()){ + Static.halt(); + } + else{ + Print.log("Provided Modelbase is NULL, expect errors!", object); + }*/ + } + if(object.has(string) && object.get(string).isJsonArray()){ + return parse(base, object.get(string).getAsJsonArray(), tx, ty); + } + return new ModelRendererTurbo[0]; + } + + public static final float get(String s, JsonObject obj, float def){ + if(obj.has(s)){ + return obj.get(s).getAsFloat(); + } + return def; + } + + public static final float get(String[] s, JsonObject obj, float def){ + for(String str : s){ + if(obj.has(str)){ + return obj.get(str).getAsFloat(); + } + } + return 0; + } + + public static final int get(String[] s, JsonObject obj, int def){ + for(String str : s){ + if(obj.has(str)){ + return obj.get(str).getAsInt(); + } + } + return 0; + } + +} \ No newline at end of file diff --git a/src/main/java/fexcraft/tmt/slim/ModelBase.java b/src/main/java/fexcraft/tmt/slim/ModelBase.java new file mode 100644 index 0000000000..edf8909e67 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/ModelBase.java @@ -0,0 +1,350 @@ +package fexcraft.tmt.slim; + +import ebf.tim.utility.CommonUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.entity.Entity; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** +* Similar to 'FlansMod'-type Models, for a fast convert. +* @Author Ferdinand Calo' (FEX___96) +*/ +public class ModelBase extends ArrayList { + + @Deprecated //box list for static parts should be completley unnecessary by making a displaylist of it as a whole. + //improvements can be further made by having a Map for the static parts, so each intance ever only + // exists once on GPU, so 40 boxcar bases would still be the animated parts + // and a single static to cover all of them. + public List boxList = new ArrayList<>(); + public List namedList = new ArrayList<>(); + public List creators = new ArrayList<>(); + public boolean init=true; + public ModelRendererTurbo base[],bodyModel[],open[],closed[],r1[],r2[],r3[],r4[],r5[],r6[],r7[],r8[],r9[],r0[]; + + public List displayList=new ArrayList<>(); + + public static Map staticPartMap = new HashMap<>(); + public Integer localGLID = null; + + public static boolean disableCache=false; + public static boolean EnableAnimations=false; + + public void render(){ + if(init){ + initAllParts(); + } + + if(disableCache) { + render(boxList); + } else if(localGLID!=null && GL11.glIsList(localGLID)) { + GL11.glCallList(localGLID); + } else if(staticPartMap.get(this.getClass().getName())==null || !GL11.glIsList(staticPartMap.get(this.getClass().getName()))) { + localGLID=GLAllocation.generateDisplayLists(1); + staticPartMap.put(this.getClass().getName(), localGLID); + GL11.glNewList(localGLID, GL11.GL_COMPILE); + render(boxList); + GL11.glEndList(); + if(!EnableAnimations) { + boxList = null; + } + } else { + localGLID=staticPartMap.get(this.getClass().getName()); + GL11.glCallList(localGLID); + } + + + if(namedList ==null){return;} + ModelRendererTurbo part; + for(int i = 0; i< namedList.size(); i++){ + //for animations to work we have to limit the displaylist cache to ONLY the geometry, and then + // the position and offsets must be done manually every frame. + if(displayList.size()>i){ + part= namedList.get(i); + if(!part.showModel){ + continue; + } + GL11.glPushMatrix(); + if (part.ignoresLighting){ + Minecraft.getMinecraft().entityRenderer.disableLightmap(1D); + } + GL11.glTranslatef(part.rotationPointX * 0.0625F, part.rotationPointY * 0.0625F, part.rotationPointZ * 0.0625F); + GL11.glRotatef(part.rotateAngleY, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(part.rotateAngleZ, 0.0F, 0.0F, 1.0F); + GL11.glRotatef(part.rotateAngleX, 1.0F, 0.0F, 0.0F); + if(GL11.glIsList(displayList.get(i))) { + GL11.glCallList(displayList.get(i)); + } else { + int disp = GLAllocation.generateDisplayLists(1); + displayList.set(i,disp); + GL11.glNewList(disp, GL11.GL_COMPILE); + for (TexturedPolygon poly : namedList.get(i).faces) { + Tessellator.getInstance().drawTexturedVertsWithNormal(poly, 0.0625F); + } + GL11.glEndList(); + } + + GL11.glTranslatef(-part.rotationPointX * 0.0625F, -part.rotationPointY * 0.0625F, -part.rotationPointZ * 0.0625F); + if (part.ignoresLighting){ + Minecraft.getMinecraft().entityRenderer.enableLightmap(1D); + } + GL11.glPopMatrix(); + + } else if(namedList.get(i)!=null) { + int disp = GLAllocation.generateDisplayLists(1); + displayList.add(disp); + GL11.glNewList(disp, GL11.GL_COMPILE); + for (TexturedPolygon poly : namedList.get(i).faces) { + Tessellator.getInstance().drawTexturedVertsWithNormal(poly, 0.0625F); + } + GL11.glEndList(); + } + } + } + + public void renderBlock(){ + if(!init) { + initAllParts(); + } + render(boxList); + + ModelRendererTurbo part; + for(int i = 0; i< namedList.size(); i++){ + //for animations to work we have to limit the displaylist cache to ONLY the geometry, and then + // the position and offsets must be done manually every frame. + if(displayList.size()>i){ + part= namedList.get(i); + if(!part.showModel){ + continue; + } + GL11.glPushMatrix(); + if (part.ignoresLighting){ + Minecraft.getMinecraft().entityRenderer.disableLightmap(1D); + } + GL11.glTranslatef(part.rotationPointX * 0.0625F, part.rotationPointY * 0.0625F, part.rotationPointZ * 0.0625F); + GL11.glRotatef(part.rotateAngleY, 0.0F, 1.0F, 0.0F); + GL11.glRotatef(part.rotateAngleZ, 0.0F, 0.0F, 1.0F); + GL11.glRotatef(part.rotateAngleX, 1.0F, 0.0F, 0.0F); + for (TexturedPolygon poly : namedList.get(i).faces) { + Tessellator.getInstance().drawTexturedVertsWithNormal(poly, 0.0625F); + } + + GL11.glTranslatef(-part.rotationPointX * 0.0625F, -part.rotationPointY * 0.0625F, -part.rotationPointZ * 0.0625F); + if (part.ignoresLighting){ + Minecraft.getMinecraft().entityRenderer.enableLightmap(1D); + } + GL11.glPopMatrix(); + + } else if(namedList.get(i)!=null) { + for (TexturedPolygon poly : namedList.get(i).faces) { + Tessellator.getInstance().drawTexturedVertsWithNormal(poly, 0.0625F); + } + } + } + } + + /** render sub-model array */ + public void render(List model){ + if(model==null){return;} + for(ModelRendererTurbo sub : model){ + if(sub!=null) { + GL11.glPushMatrix(); + sub.render(); + GL11.glPopMatrix(); + } + } + } + + + + public void render(Object type, Entity ent){render(); } + + public void render(Entity entity, float f, float f1, float f2, float f3, float f4, float f5) {render();} + + + public void translateAll(float x, float y, float z){ + translate(base, x, y, z); + translate(open, x, y, z); + translate(closed, x, y, z); + translate(r0, x, y, z); + translate(r1, x, y, z); + translate(r2, x, y, z); + translate(r3, x, y, z); + translate(r4, x, y, z); + translate(r5, x, y, z); + translate(r6, x, y, z); + translate(r7, x, y, z); + translate(r8, x, y, z); + translate(r9, x, y, z); + translate(bodyModel,x,y,z); + translate(boxList,x,y,z); + translate(namedList,x,y,z); + } + + + public void rotateAll(float x, float y, float z){ + rotate(base, x, y, z); + rotate(open, x, y, z); + rotate(closed, x, y, z); + rotate(r0, x, y, z); + rotate(r1, x, y, z); + rotate(r2, x, y, z); + rotate(r3, x, y, z); + rotate(r4, x, y, z); + rotate(r5, x, y, z); + rotate(r6, x, y, z); + rotate(r7, x, y, z); + rotate(r8, x, y, z); + rotate(r9, x, y, z); + rotate(bodyModel,x,y,z); + rotate(boxList,x,y,z); + rotate(namedList,x,y,z); + } + public void flipAll(){ + flip(base); + flip(open); + flip(closed); + flip(r0); + flip(r1); + flip(r2); + flip(r3); + flip(r4); + flip(r5); + flip(r6); + flip(r7); + flip(r8); + flip(r9); + flip(bodyModel); + flip(boxList); + flip(namedList); + } + + + protected final void fixRotation(ModelRendererTurbo[] model, boolean flipX, boolean flipY, boolean flipZ){ + if(!flipX && !flipY && !flipZ){return;} + for(ModelRendererTurbo mod : model){ + if(mod==null){continue;} + if(flipX){mod.rotateAngleX = -mod.rotateAngleX;} + if(flipY){mod.rotateAngleY = -mod.rotateAngleY;} + if(flipZ){mod.rotateAngleZ = -mod.rotateAngleZ;} + } + } + + protected final void fixRotation(ModelRendererTurbo[] parts){ + for(ModelRendererTurbo p : parts){ + p.rotateAngleX*= CommonUtil.degreesF; + p.rotateAngleY*= CommonUtil.degreesF; + p.rotateAngleZ*= CommonUtil.degreesF; + } + } + + + protected void translate(ModelRendererTurbo[] model, float x, float y, float z){ + if(model==null){return;} + for(ModelRendererTurbo mod : model){ + if(mod==null){continue;} + mod.rotationPointX += x; + mod.rotationPointY += y; + mod.rotationPointZ += z; + } + } + protected void translate(List model, float x, float y, float z){ + if(model==null){return;} + for(ModelRendererTurbo mod : model){ + if(mod==null){continue;} + mod.rotationPointX += x; + mod.rotationPointY += y; + mod.rotationPointZ += z; + } + } + + protected void rotate(ModelRendererTurbo[] model, float x, float y, float z) { + if(model==null){return;} + for(ModelRendererTurbo mod : model){ + if(mod==null){continue;} + mod.rotateAngleX += x; + mod.rotateAngleY += y; + mod.rotateAngleZ += z; + } + } + protected void rotate(List model, float x, float y, float z) { + if(model==null){return;} + for(ModelRendererTurbo mod : model){ + if(mod==null){continue;} + mod.rotateAngleX += x; + mod.rotateAngleY += y; + mod.rotateAngleZ += z; + } + } + + public void flip(ModelRendererTurbo[] model) { + if(model==null){return;} + for(ModelRendererTurbo mod : model){ + if(mod==null){continue;} + mod.rotateAngleY = -mod.rotateAngleY * 57.29578F; + mod.rotateAngleZ = -mod.rotateAngleZ * 57.29578F; + mod.rotateAngleX *= 57.29578F; + } + } + public void flip(List model) { + if(model==null){return;} + for(ModelRendererTurbo sub : model){ + if(sub==null){continue;} + sub.doMirror(false, true, true); + sub.setRotationPoint(sub.rotationPointX, -sub.rotationPointY, -sub.rotationPointZ); + } + } + + public List getnamedParts(){ + if(init){ + initAllParts(); + } + return namedList; + } + + public void addPart(ModelRendererTurbo part){ + if(part==null) { + return; + }if(part.boxName!=null && part.boxName.length()>2){ + namedList.add(part); + } else { + boxList.add(part); + } + } + + public void addToCreators(String s){ + creators.add(s); + } + + + public void initAllParts(){ + base=initList(base); + open=initList(open); + closed=initList(closed); + bodyModel=initList(bodyModel); + r0=initList(r0); + r1=initList(r1); + r2=initList(r2); + r3=initList(r3); + r4=initList(r4); + r5=initList(r5); + r6=initList(r6); + r7=initList(r7); + r8=initList(r8); + r9=initList(r9); + init=false; + } + + public ModelRendererTurbo[] initList(ModelRendererTurbo[] list){ + if(list==null){return null;} + for(ModelRendererTurbo model : list){ + addPart(model); + } + return null; + } +} diff --git a/src/main/java/fexcraft/tmt/slim/ModelConverter.java b/src/main/java/fexcraft/tmt/slim/ModelConverter.java new file mode 100644 index 0000000000..c38ac4075d --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/ModelConverter.java @@ -0,0 +1,106 @@ +package fexcraft.tmt.slim; + +/** +* Converter to use Flansmod-Type vehicle models. +* @Author Ferdinand Calo' (FEX___96) +*/ +public class ModelConverter extends ModelBase { + + public ModelRendererTurbo model[],bodyDoorOpenModel[], bodyDoorCloseModel[],trailerModel[],steeringWheelModel[]; + + public ModelRendererTurbo turretModel[],barrelModel[]; + public ModelRendererTurbo frontWheelModel[],backWheelModel[], + leftFrontWheelModel[],rightFrontWheelModel[],leftBackWheelModel[],rightBackWheelModel[]; + public ModelRendererTurbo rightTrackModel[],leftTrackModel[], + rightTrackWheelModels[],leftTrackWheelModels[]; + + @Override + public void initAllParts(){ + model=initList(model); + bodyDoorOpenModel=initList(bodyDoorOpenModel); + bodyDoorCloseModel=initList(bodyDoorCloseModel); + trailerModel=initList(trailerModel); + steeringWheelModel=initList(steeringWheelModel); + turretModel=initList(turretModel); + barrelModel=initList(barrelModel); + frontWheelModel=initList(frontWheelModel); + backWheelModel=initList(backWheelModel); + leftFrontWheelModel=initList(leftFrontWheelModel); + rightFrontWheelModel=initList(rightFrontWheelModel); + leftBackWheelModel=initList(leftBackWheelModel); + rightBackWheelModel=initList(rightBackWheelModel); + rightTrackModel=initList(rightTrackModel); + leftTrackModel=initList(leftTrackModel); + rightTrackWheelModels=initList(rightTrackWheelModels); + leftTrackWheelModels=initList(leftTrackWheelModels); + super.initAllParts(); + } + + + @Override + public void translateAll(float x, float y, float z){ + super.translateAll(x,y,z); + translate(model, x, y, z); + translate(bodyDoorOpenModel, x, y, z); + translate(bodyDoorCloseModel, x, y, z); + translate(turretModel, x, y, z); + translate(barrelModel, x, y, z); + translate(frontWheelModel, x, y, z); + translate(backWheelModel, x, y, z); + translate(leftFrontWheelModel, x, y, z); + translate(rightFrontWheelModel, x, y, z); + translate(leftBackWheelModel, x, y, z); + translate(rightBackWheelModel, x, y, z); + translate(rightTrackModel, x, y, z); + translate(leftTrackModel, x, y, z); + translate(rightTrackWheelModels, x, y, z); + translate(leftTrackWheelModels, x, y, z); + translate(trailerModel, x, y, z); + translate(steeringWheelModel, x, y, z); + } + + @Override + public void rotateAll(float x, float y, float z){ + super.rotateAll(x,y,z); + rotate(model, x, y, z); + rotate(bodyDoorOpenModel, x, y, z); + rotate(bodyDoorCloseModel, x, y, z); + rotate(turretModel, x, y, z); + rotate(barrelModel, x, y, z); + rotate(frontWheelModel, x, y, z); + rotate(backWheelModel, x, y, z); + rotate(leftFrontWheelModel, x, y, z); + rotate(rightFrontWheelModel, x, y, z); + rotate(leftBackWheelModel, x, y, z); + rotate(rightBackWheelModel, x, y, z); + rotate(rightTrackModel, x, y, z); + rotate(leftTrackModel, x, y, z); + rotate(rightTrackWheelModels, x, y, z); + rotate(leftTrackWheelModels, x, y, z); + rotate(trailerModel, x, y, z); + rotate(steeringWheelModel, x, y, z); + } + + @Override + public void flipAll(){ + super.flipAll(); + flip(model); + flip(bodyDoorOpenModel); + flip(bodyDoorCloseModel); + flip(turretModel); + flip(barrelModel); + flip(frontWheelModel); + flip(backWheelModel); + flip(leftFrontWheelModel); + flip(rightFrontWheelModel); + flip(leftBackWheelModel); + flip(rightBackWheelModel); + flip(rightTrackModel); + flip(leftTrackModel); + flip(rightTrackWheelModels); + flip(leftTrackWheelModels); + flip(trailerModel); + flip(steeringWheelModel); + } + +} diff --git a/src/main/java/fexcraft/tmt/slim/ModelPool.java b/src/main/java/fexcraft/tmt/slim/ModelPool.java new file mode 100644 index 0000000000..7c523ae2e0 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/ModelPool.java @@ -0,0 +1,76 @@ +package fexcraft.tmt.slim; + +import cpw.mods.fml.common.Loader; +import org.apache.commons.io.IOUtils; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +public class ModelPool { + + public static ModelPoolEntry addFile(String file, Class modelClass){ + ModelPoolEntry entry = null; + if(modelMap.containsKey(file)){ + entry = modelMap.get(file); + return entry; + } + try{ + entry = (ModelPoolEntry)modelClass.newInstance(); + } + catch(Exception e){ + System.out.println("A new " + entry.getClass().getName() + " could not be initialized."); + System.out.println(e.getMessage()); + return null; + } + InputStream modelFile = entry.checkValidPath(file.substring(5)); + if(modelFile == null){ + System.out.println("The model with the name " + file + " does not exist."); + return null; + } + entry.textures = new HashMap(); + entry.name = file; + entry.setTextureGroup("0"); + entry.getModel(modelFile); + modelMap.put(file, entry); + return entry; + } + + public static ModelPoolEntry addFileF(String file, Class modelClass) throws IOException{ + ModelPoolEntry entry = null; + if(modelMap.containsKey(file)){ + entry = modelMap.get(file); + return entry; + } + try{ + entry = (ModelPoolEntry)modelClass.newInstance(); + } + catch(Exception e){ + System.out.println("A new " + entry.getClass().getName() + " could not be initialized."); + System.out.println(e.getMessage()); + return null; + } + InputStream in = entry.getClass().getResourceAsStream("/assets/" + file + ".obj"); + if(in == null){ + System.out.println("The model with the name " + file + " does not exist."); + return null; + } + entry.textures = new HashMap(); + entry.name = file; + entry.setTextureGroup("0"); + entry.getModel(in); + modelMap.put(file, entry); + return entry; + } + + private static Map modelMap = new HashMap(); + private static String[] resourceDir = new String[] { + "minecraft/resources/models/", + "minecraft/resources/mod/models/" + }; + public static final Class OBJ = ModelPoolObjEntry.class; + +} diff --git a/src/main/java/fexcraft/tmt/slim/ModelPoolEntry.java b/src/main/java/fexcraft/tmt/slim/ModelPoolEntry.java new file mode 100644 index 0000000000..ebf3412115 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/ModelPoolEntry.java @@ -0,0 +1,39 @@ +package fexcraft.tmt.slim; + +import java.io.File; +import java.io.InputStream; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; + +public abstract class ModelPoolEntry { + + public String name; + public TexturedVertex[] vertices; + public TexturedPolygon[] faces; + public Map textures; + protected TextureGroup texture; + + public InputStream checkValidPath(String path){ + return getClass().getResourceAsStream(path); + } + + public abstract void getModel(InputStream file); + + /** + * Sets the current texture group, which is used to switch the + * textures on a per-model base. Do note that any model that is + * rendered afterwards will use the same texture. To counter it, + * set a default texture, either at initialization or before + * rendering. + * @param groupName The name of the texture group. If the texture + * group doesn't exist, it creates a new group automatically. + */ + protected void setTextureGroup(String groupName){ + if(textures.size() == 0 || !textures.containsKey(groupName)){ + textures.put(groupName, new TextureGroup()); + } + texture = textures.get(groupName); + } + +} diff --git a/src/main/java/fexcraft/tmt/slim/ModelPoolObjEntry.java b/src/main/java/fexcraft/tmt/slim/ModelPoolObjEntry.java new file mode 100644 index 0000000000..5e85531d82 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/ModelPoolObjEntry.java @@ -0,0 +1,189 @@ +package fexcraft.tmt.slim; + +import java.io.*; +import java.util.ArrayList; + +public class ModelPoolObjEntry extends ModelPoolEntry { + + public ModelPoolObjEntry(){} + + public void getModel(InputStream file){ + try{ + BufferedReader in = new BufferedReader(new InputStreamReader(file)); + String s; + ArrayList verts = new ArrayList(); + ArrayList uvs = new ArrayList(); + ArrayList normals = new ArrayList(); + ArrayList face = new ArrayList(); + while((s = in.readLine()) != null){ + if(s.contains("#")){ + s = s.substring(0, s.indexOf("#")); + } + s = s.trim(); + if(s.equals("")){ + continue; + } + if(s.startsWith("g ")){ + setTextureGroup(s.substring(s.indexOf(" ") + 1).trim()); + continue; + } + if(s.startsWith("v ")){ + s = s.substring(s.indexOf(" ") + 1).trim(); + float[] v = new float[3]; + for(int i = 0; i < 3; i++){ + int ind = s.indexOf(" "); + if(ind > -1){ + v[i] = Float.parseFloat(s.substring(0, ind)); + } + else{ + v[i] = Float.parseFloat(s.substring(0)); + } + s = s.substring(s.indexOf(" ") + 1).trim(); + } + float flt = v[2]; + v[2] = -v[1]; + v[1] = flt; + verts.add(new TexturedVertex(v[0], v[1], v[2], 0, 0)); + continue; + } + if(s.startsWith("vt ")){ + s = s.substring(s.indexOf(" ") + 1).trim(); + float[] v = new float[2]; + for(int i = 0; i < 2; i++){ + int ind = s.indexOf(" "); + if(ind > -1){ + v[i] = Float.parseFloat(s.substring(0, ind)); + } + else{ + v[i] = Float.parseFloat(s.substring(0)); + } + s = s.substring(s.indexOf(" ") + 1).trim(); + } + uvs.add(new float[] {v[0], 1F - v[1]}); + continue; + } + if(s.startsWith("vn ")){ + s = s.substring(s.indexOf(" ") + 1).trim(); + float[] v = new float[3]; + for(int i = 0; i < 3; i++){ + int ind = s.indexOf(" "); + if(ind > -1){ + v[i] = Float.parseFloat(s.substring(0, ind)); + } + else{ + v[i] = Float.parseFloat(s.substring(0)); + } + s = s.substring(s.indexOf(" ") + 1).trim(); + } + float flt = v[2]; + v[2] = v[1]; + v[1] = flt; + normals.add(new float[] {v[0], v[1], v[2]}); + continue; + } + if(s.startsWith("f ")){ + s = s.substring(s.indexOf(" ") + 1).trim(); + ArrayList v = new ArrayList(); + String s1; + int finalPhase = 0; + float[] normal = new float[] {0F, 0F, 0F}; + ArrayList iNormal = new ArrayList(); + do{ + int vInt; + float[] curUV; + float[] curNormals; + int ind = s.indexOf(" "); + s1 = s; + if(ind > -1){ + s1 = s.substring(0, ind); + } + if(s1.indexOf("/") > -1){ + String[] f = s1.split("/"); + vInt = Integer.parseInt(f[0]) - 1; + if(f[1].equals("")){ + f[1] = f[0]; + } + int vtInt = Integer.parseInt(f[1]) - 1; + if(uvs.size() > vtInt){ + curUV = uvs.get(vtInt); + } + else{ + curUV = new float[] {0, 0}; + } + int vnInt = 0; + if(f.length == 3){ + if(f[2].equals("")){ + f[2] = f[0]; + } + vnInt = Integer.parseInt(f[2]) - 1; + } + else{ + vnInt = Integer.parseInt(f[0]) - 1; + } + if(normals.size() > vnInt){ + curNormals = normals.get(vnInt); + } + else{ + curNormals = new float[] {0, 0, 0}; + } + } + else{ + vInt = Integer.parseInt(s1) - 1; + if(uvs.size() > vInt){ + curUV = uvs.get(vInt); + } + else{ + curUV = new float[] {0, 0}; + } + if(normals.size() > vInt){ + curNormals = normals.get(vInt); + } + else{ + curNormals = new float[] {0, 0, 0}; + } + } + iNormal.add(new Vec3f(curNormals[0], curNormals[1], curNormals[2])); + normal[0]+= curNormals[0]; + normal[1]+= curNormals[1]; + normal[2]+= curNormals[2]; + if(vInt < verts.size()){ + v.add(verts.get(vInt).setTexturePosition(curUV[0], curUV[1])); + } + if(ind > -1){ + s = s.substring(s.indexOf(" ") + 1).trim(); + } + else{ + finalPhase++; + } + } + while(finalPhase < 1); + float d = (float)Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]); + normal[0]/= d; + normal[1]/= d; + normal[2]/= d; + TexturedVertex[] vToArr = new TexturedVertex[v.size()]; + for(int i = 0; i < v.size(); i++){ + vToArr[i] = v.get(i); + } + TexturedPolygon poly = new TexturedPolygon(vToArr); + face.add(poly); + texture.addPoly(poly); + continue; + } + } + vertices = new TexturedVertex[verts.size()]; + for(int i = 0; i < verts.size(); i++){ + vertices[i] = verts.get(i); + } + faces = new TexturedPolygon[face.size()]; + for(int i = 0; i < face.size(); i++){ + faces[i] = face.get(i); + } + in.close(); + } + catch(Throwable e){ + // + } + } + +} \ No newline at end of file diff --git a/src/main/java/fexcraft/tmt/slim/ModelRendererTurbo.java b/src/main/java/fexcraft/tmt/slim/ModelRendererTurbo.java new file mode 100644 index 0000000000..8cb4c7c0c9 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/ModelRendererTurbo.java @@ -0,0 +1,1458 @@ +package fexcraft.tmt.slim; + +import fexcraft.fvtm.TurboList; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GLAllocation; +import net.minecraft.util.MathHelper; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; +import java.util.*; + +/** + * An extension to the ModelRenderer class. It basically is a copy to ModelRenderer, + * however, it contains various new methods to make your models. + *

+ * Since the ModelRendererTurbo class gets loaded during startup, the models made + * can be very complex. This is why I can afford to add, for example, Wavefont OBJ + * support or have the addSprite method, methods that add a lot of vertices and + * polygons. + * + * This version of TMT was updated, maintened, as well as extended for 1.8 and newer Minecraft versions by FEX___96 + * + * @author GaryCXJk, Ferdinand (FEX___96) + * @license http://fexcraft.net/license?id=tmt + * + */ +public class ModelRendererTurbo { + + public List faces; + public int textureOffsetX, textureOffsetY; + public float textureWidth=0,textureHeight=0; + public boolean mirror; + public float rotateAngleX=0,rotateAngleY=0,rotateAngleZ=0; + public float rotationPointX=0,rotationPointY=0,rotationPointZ=0; + public float width, height, depth; + public boolean showModel; //previously known as !field_1402_i + public boolean noCull=false; + public boolean ignoresLighting=false; + public String boxName = null; + public boolean animated=false; + public Integer glID=null; + + public static final int MR_FRONT = 0, MR_BACK = 1, MR_LEFT = 2, MR_RIGHT = 3, MR_TOP = 4, MR_BOTTOM = 5; + public static final float pi = (float)Math.PI; + + /** + * Creates a new ModelRenderTurbo object. + * @param s + */ + public ModelRendererTurbo(String s){ + mirror = false; + showModel = true; + faces = new ArrayList<>(); + boxName = s; + } + + /** + * Creates a new ModelRenderTurbo object. It requires the coordinates of the + * position of the texture, but also allows you to specify the width and height + * of the texture. + * @param s + * @param textureX + * @param textureY + * @param textureU + * @param textureV + */ + public ModelRendererTurbo(String s, int textureX, int textureY, float textureU, float textureV){ + mirror = false; + showModel = true; + faces = new ArrayList<>(); + boxName = s; + textureOffsetX = textureX; + textureOffsetY = textureY; + textureWidth = textureU; + textureHeight = textureV; + } + + public ModelRendererTurbo(ModelBase modelbase, String s){this(s);} + public ModelRendererTurbo(TurboList modelbase, String s){this(s);} + public ModelRendererTurbo(ModelBase modelbase){this("");} + + public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY, int textureU, int textureV){ + this("",textureX,textureY,textureU,textureV); + } + public ModelRendererTurbo(TurboList modelbase, int textureX, int textureY, int textureU, int textureV){ + this("",textureX,textureY,textureU,textureV); + } + public ModelRendererTurbo(ModelBase modelbase, int textureX, int textureY, int textureU, int textureV, String boxName) { + this(boxName,textureX,textureY,textureU,textureV); + } + + + private TexturedPolygon textureQuad(TexturedVertex vert1, TexturedVertex vert2, TexturedVertex vert3, TexturedVertex vert4, float f, float g, float h, float j){ + float uOffs = 1.0F / (textureWidth * 10.0F); + float vOffs = 1.0F / (textureHeight * 10.0F); + List verts = new ArrayList<>(); + //todo: use the longest, or shortest for that side for h/f g/j respectively + verts.add(vert1.setTexturePosition(h / textureWidth - uOffs, g / textureHeight + vOffs)); + verts.add(vert2.setTexturePosition(f / textureWidth + uOffs, g / textureHeight + vOffs)); + verts.add(vert3.setTexturePosition(f / textureWidth + uOffs, j / textureHeight - vOffs)); + verts.add(vert4.setTexturePosition(h / textureWidth - uOffs, j / textureHeight - vOffs)); + return new TexturedPolygon(verts); + } + + /** + * Adds a rectangular shape. Basically, you can make any eight-pointed shape you want, + * as the method requires eight vector coordinates. + * @param v a float array with three values, the x, y and z coordinates of the vertex + * @param v1 a float array with three values, the x, y and z coordinates of the vertex + * @param v2 a float array with three values, the x, y and z coordinates of the vertex + * @param v3 a float array with three values, the x, y and z coordinates of the vertex + * @param v4 a float array with three values, the x, y and z coordinates of the vertex + * @param v5 a float array with three values, the x, y and z coordinates of the vertex + * @param v6 a float array with three values, the x, y and z coordinates of the vertex + * @param v7 a float array with three values, the x, y and z coordinates of the vertex + * @param w the width of the shape, used in determining the texture + * @param h the height of the shape, used in determining the texture + * @param d the depth of the shape, used in determining the texture + */ + public ModelRendererTurbo addRectShape(float[] v, float[] v1, float[] v2, float[] v3, float[] v4, float[] v5, float[] v6, float[] v7, float w, float h, float d, boolean[] sides){ + List poly = new ArrayList<>(); + TexturedVertex vert0 = new TexturedVertex(v[0], v[1], v[2], 0.0F, 0.0F); + TexturedVertex vert1 = new TexturedVertex(v1[0], v1[1], v1[2], 0.0F, 8.0F); + TexturedVertex vert2 = new TexturedVertex(v2[0], v2[1], v2[2], 8.0F, 8.0F); + TexturedVertex vert3 = new TexturedVertex(v3[0], v3[1], v3[2], 8.0F, 0.0F); + TexturedVertex vert4 = new TexturedVertex(v4[0], v4[1], v4[2], 0.0F, 0.0F); + TexturedVertex vert5 = new TexturedVertex(v5[0], v5[1], v5[2], 0.0F, 8.0F); + TexturedVertex vert6 = new TexturedVertex(v6[0], v6[1], v6[2], 8.0F, 8.0F); + TexturedVertex vert7 = new TexturedVertex(v7[0], v7[1], v7[2], 8.0F, 0.0F); + + if(w % 1 != 0){ + w = w < 1 ? 1 : (int)w + (w % 1 > 0.5f ? 1 : 0); + } + if(h % 1 != 0){ + h = h < 1 ? 1 : (int)h + (h % 1 > 0.5f ? 1 : 0); + } + if(d % 1 != 0){ + d = d < 1 ? 1 : (int)d + (d % 1 > 0.5f ? 1 : 0); + } + if(sides == null){ + poly.add(textureQuad(vert5, vert1, vert2, vert6, textureOffsetX + d + w, textureOffsetY + d, textureOffsetX + d + w + d, textureOffsetY + d + h)); + poly.add(textureQuad(vert0, vert4, vert7, vert3, textureOffsetX, textureOffsetY + d, textureOffsetX + d, textureOffsetY + d + h)); + poly.add(textureQuad(vert5, vert4, vert0, vert1, textureOffsetX + d, textureOffsetY, textureOffsetX + d + w, textureOffsetY + d)); + poly.add(textureQuad(vert2, vert3, vert7, vert6, textureOffsetX + d + w, textureOffsetY, textureOffsetX + d + w + w, textureOffsetY + d)); + poly.add(textureQuad(vert1, vert0, vert3, vert2, textureOffsetX + d, textureOffsetY + d, textureOffsetX + d + w, textureOffsetY + d + h)); + poly.add(textureQuad(vert4, vert5, vert6, vert7, textureOffsetX + d + w + d, textureOffsetY + d, textureOffsetX + d + w + d + w, textureOffsetY + d + h)); + } else{ + float v0 = sides[2] && sides[3] ? 0 : d; + float u0 = sides[1] ? 0 : d, u1 = sides[2] ? 0 : w, u2 = sides[4] ? 0 : w, u3 = sides[0] ? 0 : d; + if(!sides[0]){poly.add(textureQuad(vert5, vert1, vert2, vert6, textureOffsetX + u0 + u2, textureOffsetY + v0, textureOffsetX + u0 + u2 + d, textureOffsetY + v0 + h));} + if(!sides[1]){poly.add(textureQuad(vert0, vert4, vert7, vert3, textureOffsetX, textureOffsetY + v0, textureOffsetX + d, textureOffsetY + v0 + h));} + if(!sides[2]){poly.add(textureQuad(vert5, vert4, vert0, vert1, textureOffsetX + u0, textureOffsetY, textureOffsetX + u0 + w, textureOffsetY + d));} + if(!sides[3]){poly.add(textureQuad(vert2, vert3, vert7, vert6, textureOffsetX + u0 + u1, textureOffsetY, textureOffsetX + u0 + u1 + w, textureOffsetY + d));} + if(!sides[4]){poly.add(textureQuad(vert1, vert0, vert3, vert2, textureOffsetX + u0, textureOffsetY + v0, textureOffsetX + u0 + w, textureOffsetY + v0 + h));} + if(sides.length > 5 && !sides[5]){poly.add(textureQuad(vert4, vert5, vert6, vert7, textureOffsetX + u0 + u2 + u3, textureOffsetY + v0, textureOffsetX + u0 + u2 + u3 + w, textureOffsetY + v0 + h));} + } + if(mirror){ + for(TexturedPolygon p : poly){ + p.flipFace(); + } + } + faces.addAll(poly); + return this; + } + + + /** + * Adds a new box to the model. + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + */ + public ModelRendererTurbo addBox(float x, float y, float z, int w, int h, int d){ + addBox(x, y, z, w, h, d, 0.0F); + return this; + } + + public ModelRendererTurbo addBox(float x, float y, float z, float w, float h, float d){ + addBox(x, y, z, w, h, d, 0.0F, 1F); + return this; + } + + /** + * Adds a new box to the model. + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param expansion the expansion of the box. It increases the size in each direction by that many. + */ + public ModelRendererTurbo addBox(float x, float y, float z, int w, int h, int d, float expansion){ + return addBox(x, y, z, w, h, d, expansion, 1F); + } + + + + public ModelRendererTurbo addBox(float x, float y, float z, float w, float h, float d, float expansion, float scale){ + return addBox(x, y, z, w, h, d, expansion, scale,null); + } + + /** + * Adds a new box to the model. + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param expansion the expansion of the box. It increases the size in each direction by that many. It's independent from the scale. + * @param scale + */ + public ModelRendererTurbo addBox(float x, float y, float z, float w, float h, float d, float expansion, float scale, boolean[] sides){ + width=w;height=h;depth=d; + expansion +=0.005f; + float x1 = (x + w+expansion)*scale; + float y1 = (y + h+expansion)*scale; + float z1 = (z + d+expansion)*scale; + + x -= expansion; x*=scale; + y -= expansion; y*=scale; + z -= expansion; z*=scale; + if(mirror){ + float xTemp = x1; + x1 = x; + x = xTemp; + } + + float[] v = {x, y, z}; + float[] v1 = {x1, y, z}; + float[] v2 = {x1, y1, z}; + float[] v3 = {x, y1, z}; + float[] v4 = {x, y, z1}; + float[] v5 = {x1, y, z1}; + float[] v6 = {x1, y1, z1}; + float[] v7 = {x, y1, z1}; + return addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d,sides); + } + + /** + * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. + * You can use the static variables MR_RIGHT, MR_LEFT, + * MR_FRONT, MR_BACK, MR_TOP and + * MR_BOTTOM. + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param scale the "scale" of the box. It only increases the size in each direction by that many. + * @param bottomScale the "scale" of the bottom + * @param dir the side the scaling is applied to + */ + public void addTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bottomScale, int dir){ + float f4 = x + w; + float f5 = y + h; + float f6 = z + d; + x -= scale; + y -= scale; + z -= scale; + f4 += scale; + f5 += scale; + f6 += scale; + + int m = (mirror ? -1 : 1); + if(mirror){ + float f7 = f4; + f4 = x; + x = f7; + } + float[] v = {x, y, z}; + float[] v1 = {f4, y, z}; + float[] v2 = {f4, f5, z}; + float[] v3 = {x, f5, z}; + float[] v4 = {x, y, f6}; + float[] v5 = {f4, y, f6}; + float[] v6 = {f4, f5, f6}; + float[] v7 = {x, f5, f6}; + + switch(dir){ + case MR_RIGHT: + v[1] -= bottomScale; + v[2] -= bottomScale; + v3[1] += bottomScale; + v3[2] -= bottomScale; + v4[1] -= bottomScale; + v4[2] += bottomScale; + v7[1] += bottomScale; + v7[2] += bottomScale; + break; + case MR_LEFT: + v1[1] -= bottomScale; + v1[2] -= bottomScale; + v2[1] += bottomScale; + v2[2] -= bottomScale; + v5[1] -= bottomScale; + v5[2] += bottomScale; + v6[1] += bottomScale; + v6[2] += bottomScale; + break; + case MR_FRONT: + v[0] -= m * bottomScale; + v[1] -= bottomScale; + v1[0] += m * bottomScale; + v1[1] -= bottomScale; + v2[0] += m * bottomScale; + v2[1] += bottomScale; + v3[0] -= m * bottomScale; + v3[1] += bottomScale; + break; + case MR_BACK: + v4[0] -= m * bottomScale; + v4[1] -= bottomScale; + v5[0] += m * bottomScale; + v5[1] -= bottomScale; + v6[0] += m * bottomScale; + v6[1] += bottomScale; + v7[0] -= m * bottomScale; + v7[1] += bottomScale; + break; + case MR_TOP: + v[0] -= m * bottomScale; + v[2] -= bottomScale; + v1[0] += m * bottomScale; + v1[2] -= bottomScale; + v4[0] -= m * bottomScale; + v4[2] += bottomScale; + v5[0] += m * bottomScale; + v5[2] += bottomScale; + break; + case MR_BOTTOM: + v2[0] += m * bottomScale; + v2[2] -= bottomScale; + v3[0] -= m * bottomScale; + v3[2] -= bottomScale; + v6[0] += m * bottomScale; + v6[2] += bottomScale; + v7[0] -= m * bottomScale; + v7[2] += bottomScale; + break; + } + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d,null); + } + + /** + * Adds a trapezoid-like shape. It's achieved by expanding the shape on one side. + * You can use the static variables MR_RIGHT, MR_LEFT, + * MR_FRONT, MR_BACK, MR_TOP and + * MR_BOTTOM. + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width (over the x-direction) + * @param h the height (over the y-direction) + * @param d the depth (over the z-direction) + * @param scale the "scale" of the box. It only increases the size in each direction by that many. + * @param bScale1 the "scale" of the bottom - Top + * @param bScale2 the "scale" of the bottom - Bottom + * @param bScale3 the "scale" of the bottom - Left + * @param bScale4 the "scale" of the bottom - Right + * @param fScale1 the "scale" of the top - Left + * @param fScale2 the "scale" of the top - Right + * @param dir the side the scaling is applied to + */ + public void addFlexTrapezoid(float x, float y, float z, int w, int h, int d, float scale, float bScale1, float bScale2, float bScale3, float bScale4, float fScale1, float fScale2, int dir) + { + float f4 = x + w; + float f5 = y + h; + float f6 = z + d; + x -= scale; + y -= scale; + z -= scale; + f4 += scale; + f5 += scale; + f6 += scale; + + int m = (mirror ? -1 : 1); + if(mirror) + { + float f7 = f4; + f4 = x; + x = f7; + } + + float[] v = {x, y, z}; + float[] v1 = {f4, y, z}; + float[] v2 = {f4, f5, z}; + float[] v3 = {x, f5, z}; + float[] v4 = {x, y, f6}; + float[] v5 = {f4, y, f6}; + float[] v6 = {f4, f5, f6}; + float[] v7 = {x, f5, f6}; + + + switch(dir) + { + case MR_RIGHT: + v[2] -= fScale1; + v1[2] -= fScale1; + v4[2] += fScale2; + v5[2] += fScale2; + + v[1] -= bScale1; + v[2] -= bScale3; + v3[1] += bScale2; + v3[2] -= bScale3; + v4[1] -= bScale1; + v4[2] += bScale4; + v7[1] += bScale2; + v7[2] += bScale4; + break; + case MR_LEFT: + v[2] -= fScale1; + v1[2] -= fScale1; + v4[2] += fScale2; + v5[2] += fScale2; + + v1[1] -= bScale1; + v1[2] -= bScale3; + v2[1] += bScale2; + v2[2] -= bScale3; + v5[1] -= bScale1; + v5[2] += bScale4; + v6[1] += bScale2; + v6[2] += bScale4; + break; + case MR_FRONT: + v1[1] -= fScale1; + v5[1] -= fScale1; + v2[1] += fScale2; + v6[1] += fScale2; + + v[0] -= m * bScale4; + v[1] -= bScale1; + v1[0] += m * bScale3; + v1[1] -= bScale1; + v2[0] += m * bScale3; + v2[1] += bScale2; + v3[0] -= m * bScale4; + v3[1] += bScale2; + break; + case MR_BACK: + v1[1] -= fScale1; + v5[1] -= fScale1; + v2[1] += fScale2; + v6[1] += fScale2; + + v4[0] -= m * bScale4; + v4[1] -= bScale1; + v5[0] += m * bScale3; + v5[1] -= bScale1; + v6[0] += m * bScale3; + v6[1] += bScale2; + v7[0] -= m * bScale4; + v7[1] += bScale2; + break; + case MR_TOP: + v1[2] -= fScale1; + v2[2] -= fScale1; + v5[2] += fScale2; + v6[2] += fScale2; + + v[0] -= m * bScale1; + v[2] -= bScale3; + v1[0] += m * bScale2; + v1[2] -= bScale3; + v4[0] -= m * bScale1; + v4[2] += bScale4; + v5[0] += m * bScale2; + v5[2] += bScale4; + break; + case MR_BOTTOM: + v1[2] -= fScale1; + v2[2] -= fScale1; + v5[2] += fScale2; + v6[2] += fScale2; + + v2[0] += m * bScale2; + v2[2] -= bScale3; + v3[0] -= m * bScale1; + v3[2] -= bScale3; + v6[0] += m * bScale2; + v6[2] += bScale4; + v7[0] -= m * bScale1; + v7[2] += bScale4; + break; + } + + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d,null); + } + + /** + * Creates a shape from a 2D vector shape. + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an array of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + */ + public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction){ + addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); + } + + /** + * Creates a shape from a 2D vector shape. + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an array of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + * @param faceLengths An array with the length of each face. Used to set + * the texture width of each face on the side manually. + */ + public void addShape3D(float x, float y, float z, Coord2D[] coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths){ + addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); + } + + /** + * Creates a shape from a 2D vector shape. + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an ArrayList of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + */ + public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction){ + addShape3D(x, y, z, coordinates, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); + } + + /** + * Creates a shape from a 2D vector shape. + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param coordinates an ArrayList of coordinates that form the shape + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + * @param faceLengths An array with the length of each face. Used to set + * the texture width of each face on the side manually. + */ + public void addShape3D(float x, float y, float z, ArrayList coordinates, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths){ + addShape3D(x, y, z, new Shape2D(coordinates), depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, faceLengths); + } + + /** + * Creates a shape from a 2D vector shape. + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param shape a Shape2D which contains the coordinates of the shape points + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + */ + public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction){ + addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, direction, null); + } + + /** + * Creates a shape from a 2D vector shape. + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param shape a Shape2D which contains the coordinates of the shape points + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param direction the direction the starting point of the shape is facing + * @param faceLengths An array with the length of each face. Used to set + * the texture width of each face on the side manually. + */ + public ModelRendererTurbo addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, int direction, float[] faceLengths){ + float rotX = 0; + float rotY = 0; + float rotZ = 0; + switch(direction){ + case MR_LEFT: + rotY = pi / 2; + break; + case MR_RIGHT: + rotY = -pi / 2; + break; + case MR_TOP: + rotX = pi / 2; + break; + case MR_BOTTOM: + rotX = -pi / 2; + break; + case MR_FRONT: + rotY = pi; + break; + case MR_BACK: + break; + } + return addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, faceLengths); + } + + /** + * Creates a shape from a 2D vector shape. + * @param x the starting x position + * @param y the starting y position + * @param z the starting z position + * @param shape a Shape2D which contains the coordinates of the shape points + * @param depth the depth of the shape + * @param shapeTextureWidth the width of the texture of one side of the shape + * @param shapeTextureHeight the height of the texture the shape + * @param sideTextureWidth the width of the texture of the side of the shape + * @param sideTextureHeight the height of the texture of the side of the shape + * @param rotX the rotation around the x-axis + * @param rotY the rotation around the y-axis + * @param rotZ the rotation around the z-axis + */ + public void addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ){ + addShape3D(x, y, z, shape, depth, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, rotX, rotY, rotZ, null); + } + + /** + * Eternal: the check for flip was removed, shapes always need to be flipped., added a boolean to define if it's a shape or not so we can properly fix rotations + * NOTE: `x` and `z` are inverted to prevent "Toolbox" or "Flansmod"-type models from being rendered wrong. + * There is currently no other commonly used editor for such models, so let's leave it that way for now. + * NOTE2: Also let's rotate by 180 degrees for whatever reason. + * @Ferdinand + */ + public ModelRendererTurbo addShape3D(float x, float y, float z, Shape2D shape, float depth, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float rotX, float rotY, float rotZ, float[] faceLengths){ + faces.addAll(Arrays.asList(shape.extrude(-x, y, -z, rotX, rotY, rotZ, depth, textureOffsetX, textureOffsetY, textureWidth, textureHeight, shapeTextureWidth, shapeTextureHeight, sideTextureWidth, sideTextureHeight, faceLengths))); + return this; + } + + + /** + * Creates a model shaped like the exact image on the texture by making a series of 2d planes. + * @param x the starting x-position + * @param y the starting y-position + * @param z the starting z-position + * @param w the width of the sprite + * @param h the height of the sprite + * @param extrude the expansion of the sprite on the axis that would otherwise be 0. + */ + public ModelRendererTurbo addSprite(float x, float y, float z, int w, int h, int d, float extrude){ + float x1,y1,z1,x2,y2,z2; + for(float expansion=0;expansion<=extrude;expansion+=0.2f){ + x1=(w==0?expansion:x); + y1=(h==0?expansion:y); + z1=(d==0?expansion:z); + + x2=(w==0?x+w+expansion:w); + y2=(h==0?y+h+expansion:h); + z2=(d==0?z+d+expansion:d); + + if(mirror){ + float xTemp = x1; + x1 = x; + x = xTemp; + } + + float[] v = {x2, y2, z2}, v1 = {x1, y2, z2}, v2 = {x1, y1, z2}, v3 = {x2, y1, z2}, + v4 = {x2, y2, z1}, v5 = {x1, y2, z1}, v6 = {x1, y1, z1}, v7 = {x2, y1, z1}; + addRectShape(v, v1, v2, v3, v4, v5, v6, v7, w, h, d,null); + } + return this; + } + + /** + * Adds a spherical shape. + * @param x + * @param y + * @param z + * @param r + * @param segs + * @param rings + * @param textureW + * @param textureH + */ + public ModelRendererTurbo addSphere(float x, float y, float z, float r, int segs, int rings, int textureW, int textureH){ + if(segs < 3){ + segs = 3; + } + rings++; + TexturedVertex[] tempVerts = new TexturedVertex[segs * (rings - 1) + 2]; + List poly = new ArrayList<>(); + tempVerts[0] = new TexturedVertex(x, y - r, z, 0, 0); + tempVerts[tempVerts.length - 1] = new TexturedVertex(x, y + r, z, 0, 0); + float uOffs = 1.0F / ( textureWidth * 10.0F); + float vOffs = 1.0F / ( textureHeight * 10.0F); + float texW = textureW / textureWidth - 2F * uOffs; + float texH = textureH / textureHeight - 2F * vOffs; + float segW = texW / segs; + float segH = texH / rings; + float startU = textureOffsetX / textureWidth; + float startV = textureOffsetY / textureHeight; + + List verts; + for(int j = 1; j < rings; j++){ + for(int i = 0; i < segs; i++){ + float yWidth = MathHelper.cos(-pi / 2 + (pi / rings) * j); + float yHeight = MathHelper.sin(-pi / 2 + (pi / rings) * j); + float xSize = MathHelper.sin((pi / segs) * i * 2F + pi) * yWidth; + float zSize = -MathHelper.cos((pi / segs) * i * 2F + pi) * yWidth; + int curVert = 1 + i + segs * (j - 1); + tempVerts[curVert] = new TexturedVertex(x + xSize * r, y + yHeight * r, z + zSize * r, 0, 0); + if(i > 0){ + verts = new ArrayList<>(); + if(j == 1){ + verts.add(tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j)); + verts.add(tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j)); + verts.add(tempVerts[0].setTexturePosition(startU + segW * (i - 1), startV)); + verts.add(tempVerts[0].setTexturePosition(startU + segW + segW * i, startV)); + } + else{ + verts.add(tempVerts[curVert].setTexturePosition(startU + segW * i, startV + segH * j)); + verts.add(tempVerts[curVert - 1].setTexturePosition(startU + segW * (i - 1), startV + segH * j)); + verts.add(tempVerts[curVert - 1 - segs].setTexturePosition(startU + segW * (i - 1), startV + segH * (j - 1))); + verts.add(tempVerts[curVert - segs].setTexturePosition(startU + segW * i, startV + segH * (j - 1))); + } + poly.add(new TexturedPolygon(verts)); + } + } + verts = new ArrayList<>(); + if(j == 1){ + verts.add(tempVerts[1].setTexturePosition(startU + segW * segs, startV + segH * j)); + verts.add(tempVerts[segs].setTexturePosition(startU + segW * (segs - 1), startV + segH * j)); + verts.add(tempVerts[0].setTexturePosition(startU + segW * (segs - 1), startV)); + verts.add(tempVerts[0].setTexturePosition(startU + segW * segs, startV)); + } + else{ + verts.add(tempVerts[1 + segs * (j - 1)].setTexturePosition(startU + texW, startV + segH * j)); + verts.add(tempVerts[segs * (j - 1) + segs].setTexturePosition(startU + texW - segW, startV + segH * j)); + verts.add(tempVerts[segs * (j - 1)].setTexturePosition(startU + texW - segW, startV + segH * (j - 1))); + verts.add(tempVerts[1 + segs * (j - 1) - segs].setTexturePosition(startU + texW, startV + segH * (j - 1))); + } + poly.add(new TexturedPolygon(verts)); + } + for(int i = 0; i < segs; i++){ + verts = new ArrayList<>(); + int curVert = tempVerts.length - (segs + 1); + verts.add(tempVerts[tempVerts.length - 1].setTexturePosition(startU + segW * (i + 0.5F), startV + texH)); + verts.add(tempVerts[curVert + i].setTexturePosition(startU + segW * i, startV + texH - segH)); + verts.add(tempVerts[curVert + ((i + 1) % segs)].setTexturePosition(startU + segW * (i + 1), startV + texH - segH)); + poly.add(new TexturedPolygon(verts)); + } + faces.addAll(poly); + return this; + } + + /** + * Adds a cone. + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + */ + public ModelRendererTurbo addCone(float x, float y, float z, float radius, float length, int segments){ + return addCone(x, y, z, radius, length, segments, 1F); + } + + /** + * Adds a cone. + * + * baseScale cannot be zero. If it is, it will automatically be set to 1F. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + */ + public ModelRendererTurbo addCone(float x, float y, float z, float radius, float length, int segments, float baseScale){ + return addCone(x, y, z, radius, length, segments, baseScale, MR_TOP); + } + + /** + * Adds a cone. + * + * baseScale cannot be zero. If it is, it will automatically be set to 1F. + * + * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param baseDirection the direction it faces + */ + public ModelRendererTurbo addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection){ + return addCone(x, y, z, radius, length, segments, baseScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F)); + } + + /** + * Adds a cone. + * + * baseScale cannot be zero. If it is, it will automatically be set to 1F. + * + * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + * + * The textures for the sides are placed next to each other. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param baseDirection the direction it faces + * @param textureCircleDiameterW the diameter width of the circle on the texture + * @param textureCircleDiameterH the diameter height of the circle on the texture + */ + public ModelRendererTurbo addCone(float x, float y, float z, float radius, float length, int segments, float baseScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH){ + return addCylinder(x, y, z, radius, length, segments, baseScale, 0.0F, baseDirection, textureCircleDiameterW, textureCircleDiameterH, 1, null); + } + + /** + * Adds a cylinder. + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + */ + public ModelRendererTurbo addCylinder(float x, float y, float z, float radius, float length, int segments){ + return addCylinder(x, y, z, radius, length, segments, 1F, 1F); + } + /** + * Adds a cylinder. + * + * You can make cones by either setting baseScale or topScale to zero. Setting both + * to zero will set the baseScale to 1F. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param topScale the scaling of the top. Can be negative. + */ + public ModelRendererTurbo addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale){ + return addCylinder(x, y, z, radius, length, segments, baseScale, topScale, MR_TOP); + } + + /** + * Adds a cylinder. + * + * You can make cones by either setting baseScale or topScale to zero. Setting both + * to zero will set the baseScale to 1F. + * + * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param topScale the scaling of the top. Can be negative. + * @param baseDirection the direction it faces + */ + public ModelRendererTurbo addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection){ + return addCylinder(x, y, z, radius, length, segments, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length), null); + } + + public ModelRendererTurbo addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection, Vec3f topoff){ + return addCylinder(x, y, z, radius, length, segments, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length), topoff); + } + + + + + public ModelRendererTurbo addHollowCylinder(float x, float y, float z, float radius, float radius2, float length, int segments, int seglimit, float baseScale, float topScale, int baseDirection){ + return addHollowCylinder(x, y, z, radius, radius2, length, segments, seglimit, baseScale, topScale, baseDirection, null); + } + + public ModelRendererTurbo addHollowCylinder(float x, float y, float z, float radius, float radius2, float length, int segments, int seglimit, float baseScale, float topScale, int baseDirection, Vec3f topoff){ + return addHollowCylinder(x, y, z, radius, radius2, length, segments, seglimit, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length), topoff, new boolean[4]); + } + + public ModelRendererTurbo addHollowCylinder(float x, float y, float z, float radius, float radius2, float length, int segments, int seglimit, float baseScale, float topScale, int baseDirection, Vec3f topoff, boolean[] bools){ + return addHollowCylinder(x, y, z, radius, radius2, length, segments, seglimit, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length), topoff, bools); + } + public ModelRendererTurbo addHollowCylinder(float x, float y, float z, float radius, float radius2, float length, int segments, int seglimit, float baseScale, float topScale, int baseDirection, Vec3f topoff, float topangle, boolean[] bools){ + return addHollowCylinder(x, y, z, radius, radius2, length, segments, seglimit, baseScale, topScale, baseDirection, (int)Math.floor(radius * 2F), (int)Math.floor(radius * 2F), (int)Math.floor(length), topoff, bools); + } + + /** + * Based on the addCylinder method. + * @author Ferdinand Calo' (FEX___96) + * Adds a cylinder. + * + * You can make cones by either setting baseScale or topScale to zero. Setting both + * to zero will set the baseScale to 1F. + * + * Setting the baseDirection to either MR_LEFT, MR_BOTTOM or MR_BACK will result in + * the top being placed at the (x,y,z). + * + * The textures for the base and top are placed next to each other, while the body + * will be placed below the circles. + * + * @param x the x-position of the base + * @param y the y-position of the base + * @param z the z-position of the base + * @param radius the radius of the cylinder + * @param length the length of the cylinder + * @param segments the amount of segments the cylinder is made of + * @param baseScale the scaling of the base. Can be negative. + * @param topScale the scaling of the top. Can be negative. + * @param baseDirection the direction it faces + * @param textureCircleDiameterW the diameter width of the circle on the texture + * @param textureCircleDiameterH the diameter height of the circle on the texture + * @param textureH the height of the texture of the body + */ + public ModelRendererTurbo addCylinder(float x, float y, float z, float radius, float length, int segments, float baseScale, float topScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH, int textureH, Vec3f topoff){ + if(radius < 1){ textureCircleDiameterW = 1; textureCircleDiameterH = 1; } if(length < 1){ textureH = 1; } + boolean dirTop = (baseDirection == MR_TOP || baseDirection == MR_BOTTOM); + boolean dirSide = (baseDirection == MR_RIGHT || baseDirection == MR_LEFT); + boolean dirFront = (baseDirection == MR_FRONT || baseDirection == MR_BACK); + boolean dirMirror = (baseDirection == MR_LEFT || baseDirection == MR_BOTTOM || baseDirection == MR_BACK); + boolean coneBase = (baseScale == 0); + boolean coneTop = (topScale == 0); + if(coneBase && coneTop){ baseScale = 1F; coneBase = false; } + TexturedVertex[] tempVerts = new TexturedVertex[segments * (coneBase || coneTop ? 1 : 2) + 2]; + TexturedPolygon[] poly = new TexturedPolygon[segments * (coneBase || coneTop ? 2 : 3)]; + float xLength = (dirSide ? length : 0); + float yLength = (dirTop ? length : 0); + float zLength = (dirFront ? length : 0); + float xStart = (dirMirror ? x + xLength : x); + float yStart = (dirMirror ? y + yLength : y); + float zStart = (dirMirror ? z + zLength : z); + float xEnd = (!dirMirror ? x + xLength : x) + (topoff == null ? 0 : topoff.xCoord); + float yEnd = (!dirMirror ? y + yLength : y) + (topoff == null ? 0 : topoff.yCoord); + float zEnd = (!dirMirror ? z + zLength : z) + (topoff == null ? 0 : topoff.zCoord); + tempVerts[0] = new TexturedVertex(xStart, yStart, zStart, 0, 0); + tempVerts[tempVerts.length - 1] = new TexturedVertex(xEnd, yEnd, zEnd, 0, 0); + float xCur = xStart; + float yCur = yStart; + float zCur = zStart; + float sCur = (coneBase ? topScale : baseScale); + for(int repeat = 0; repeat < (coneBase || coneTop ? 1 : 2); repeat++){ + for(int index = 0; index < segments; index++){ + float xSize = (float)((mirror ^ dirMirror ? -1 : 1) * Math.sin((pi / segments) * index * 2F + pi) * radius * sCur); + float zSize = (float)(-Math.cos((pi / segments) * index * 2F + pi) * radius * sCur); + float xPlace = xCur + (!dirSide ? xSize : 0); + float yPlace = yCur + (!dirTop ? zSize : 0); + float zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); + tempVerts[1 + index + repeat * segments] = new TexturedVertex(xPlace, yPlace, zPlace, 0, 0 ); + } + xCur = xEnd; yCur = yEnd; zCur = zEnd; sCur = topScale; + } + float uScale = 1.0F / textureWidth; + float vScale = 1.0F / textureHeight; + float uOffset = uScale / 20.0F; + float vOffset = vScale / 20.0F; + float uCircle = textureCircleDiameterW * uScale; + float vCircle = textureCircleDiameterH * vScale; + float uWidth = (uCircle * 2F - uOffset * 2F) / segments; + float vHeight = textureH * vScale - uOffset * 2f; + float uStart = textureOffsetX * uScale; + float vStart = textureOffsetY * vScale; + TexturedVertex[] vert; + + + for(int index = 0; index < segments; index++){ + int index2 = (index + 1) % segments; + float uSize = (float)(Math.sin((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset)); + float vSize = (float)(Math.cos((pi / segments) * index * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset)); + float uSize1 = (float)(Math.sin((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset)); + float vSize1 = (float)(Math.cos((pi / segments) * index2 * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset)); + + vert = new TexturedVertex[3]; + vert[0] = tempVerts[0].setTexturePosition(uStart + 0.5F * uCircle, vStart + 0.5F * vCircle); + vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + 0.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); + vert[2] = tempVerts[1 + index].setTexturePosition(uStart + 0.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); + poly[index] = new TexturedPolygon(vert); + if(!dirFront || mirror){ + poly[index].flipFace(); + } + + if(!coneBase && !coneTop){ + vert = new TexturedVertex[4]; + vert[0] = tempVerts[1 + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle); + vert[1] = tempVerts[1 + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle); + vert[2] = tempVerts[1 + segments + index2].setTexturePosition(uStart + uOffset + uWidth * (index + 1), vStart + vOffset + vCircle + vHeight); + vert[3] = tempVerts[1 + segments + index].setTexturePosition(uStart + uOffset + uWidth * index, vStart + vOffset + vCircle + vHeight); + poly[index + segments] = new TexturedPolygon(vert); + if(!dirFront || mirror){ + poly[index + segments].flipFace(); + } + } + vert = new TexturedVertex[3]; + vert[0] = tempVerts[tempVerts.length - 1].setTexturePosition(uStart + 1.5F * uCircle, vStart + 0.5F * vCircle); + vert[1] = tempVerts[tempVerts.length - 2 - index].setTexturePosition(uStart + 1.5F * uCircle + uSize1, vStart + 0.5F * vCircle + vSize1); + vert[2] = tempVerts[tempVerts.length - (1 + segments) + ((segments - index) % segments)].setTexturePosition(uStart + 1.5F * uCircle + uSize, vStart + 0.5F * vCircle + vSize); + poly[poly.length - segments + index] = new TexturedPolygon(vert); + if(!dirFront || mirror){ + poly[poly.length - segments + index].flipFace(); + } + } + faces.addAll(Arrays.asList(poly)); + return this; + } + + + public ModelRendererTurbo addHollowCylinder(float x, float y, float z, float radius, float radius2, float length, int segments, int seglimit, float baseScale, float topScale, int baseDirection, int textureCircleDiameterW, int textureCircleDiameterH, int textureH, Vec3f topoff, boolean[] bools){ + if(radius < 1){ textureCircleDiameterW = 2; textureCircleDiameterH = 2; } if(length < 1){ textureH = 2; } + boolean dirTop = (baseDirection == MR_TOP || baseDirection == MR_BOTTOM); + boolean dirSide = (baseDirection == MR_RIGHT || baseDirection == MR_LEFT); + boolean dirFront = (baseDirection == MR_FRONT || baseDirection == MR_BACK); + boolean dirMirror = (baseDirection == MR_LEFT || baseDirection == MR_BOTTOM || baseDirection == MR_BACK); + if(baseScale == 0) baseScale = 1f; if(topScale == 0) topScale = 1f; + if(segments < 3) segments = 3; if(seglimit <= 0) seglimit = segments; boolean segl = seglimit < segments; + ArrayList polis = new ArrayList<>(); + //Vertex + float xLength = (dirSide ? length : 0), yLength = (dirTop ? length : 0), zLength = (dirFront ? length : 0); + float xStart = (dirMirror ? x + xLength : x); + float yStart = (dirMirror ? y + yLength : y); + float zStart = (dirMirror ? z + zLength : z); + float xEnd = (!dirMirror ? x + xLength : x) + (topoff == null ? 0 : topoff.xCoord); + float yEnd = (!dirMirror ? y + yLength : y) + (topoff == null ? 0 : topoff.yCoord); + float zEnd = (!dirMirror ? z + zLength : z) + (topoff == null ? 0 : topoff.zCoord); + float xCur = xStart, yCur = yStart, zCur = zStart, sCur = baseScale; + //Texture + float uScale = 1.0F / textureWidth, vScale = 1.0F / textureHeight; + float uOffset = uScale / 20.0F, vOffset = vScale / 20.0F; + float uCircle = textureCircleDiameterW * uScale; + float vCircle = textureCircleDiameterH * vScale; + float uCircle2 = ((int)Math.floor(radius2 * 2F)) * uScale; + float vCircle2 = ((int)Math.floor(radius2 * 2F)) * vScale; + float uWidth = (uCircle * 2F - uOffset * 2F) / segments; + float vHeight = textureH * vScale - uOffset * 2f; + float uStart = textureOffsetX * uScale, vStart = textureOffsetY * vScale; + //Temporary Arrays + ArrayList verts0 = new ArrayList<>(); + ArrayList verts1 = new ArrayList<>(); + ArrayList verts2 = new ArrayList<>(); + ArrayList verts3 = new ArrayList<>(); + for(int repeat = 0; repeat < 2; repeat++){//top/base faces + for(int index = 0; index < segments; index++){ + float xSize = (float)((mirror ^ dirMirror ? -1 : 1) * Math.sin((pi / segments) * index * 2F + pi) * radius * sCur); + float zSize = (float)(-Math.cos((pi / segments) * index * 2F + pi) * radius * sCur); + float xPlace = xCur + (!dirSide ? xSize : 0); + float yPlace = yCur + (!dirTop ? zSize : 0); + float zPlace = zCur + (dirSide ? xSize : (dirTop ? zSize : 0)); + verts0.add(new TexturedVertex(xPlace, yPlace, zPlace, 0, 0)); + if(index == segments - 1){ + TexturedVertex copy = new TexturedVertex(verts0.get(0)); verts0.add(copy); + } + // + float xSize2 = (float)((mirror ^ dirMirror ? -1 : 1) * Math.sin((pi / segments) * index * 2F + pi) * radius2 * sCur); + float zSize2 = (float)(-Math.cos((pi / segments) * index * 2F + pi) * radius2 * sCur); + xPlace = xCur + (!dirSide ? xSize2 : 0); + yPlace = yCur + (!dirTop ? zSize2 : 0); + zPlace = zCur + (dirSide ? xSize2 : (dirTop ? zSize2 : 0)); + verts1.add(new TexturedVertex(xPlace, yPlace, zPlace, 0, 0)); + if(index == segments - 1){ + TexturedVertex copy = new TexturedVertex(verts1.get(0)); verts1.add(copy); + } + } + if(repeat == 0){ verts2.addAll(verts0); verts2.addAll(verts1); } + else{ verts3.addAll(verts0); verts3.addAll(verts1); } + float xSize, ySize; float mul = repeat == 0 ? 0.5f : 1.5f; + boolean bool = (repeat == 0) != dirFront; + if((repeat == 0 && !bools[0]) || (repeat == 1 && !bools[1])){ + for(int i = 0; i < verts0.size(); i++){ + if(i >= (verts0.size() - 1) || i >= seglimit) break; + TexturedVertex[] arr = new TexturedVertex[4]; + xSize = (float)(Math.sin((pi / segments) * i * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset)); + ySize = (float)(Math.cos((pi / segments) * i * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset)); + arr[0] = verts0.get(i).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + // + xSize = (float)(Math.sin((pi / segments) * i * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle2 - 2F * uOffset)); + ySize = (float)(Math.cos((pi / segments) * i * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle2 - 2F * vOffset)); + arr[1] = verts1.get(i).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + // + xSize = (float)(Math.sin((pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle2 - 2F * uOffset)); + ySize = (float)(Math.cos((pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle2 - 2F * vOffset)); + arr[2] = verts1.get(i + 1).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + // + xSize = (float)(Math.sin((pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : pi)) * (0.5F * uCircle - 2F * uOffset)); + ySize = (float)(Math.cos((pi / segments) * (i + 1) * 2F + (!dirTop ? 0 : pi)) * (0.5F * vCircle - 2F * vOffset)); + arr[3] = verts0.get(i + 1).setTexturePosition(uStart + mul * uCircle + xSize, vStart + 0.5F * vCircle + ySize); + polis.add(new TexturedPolygon(arr)); + if(bool) polis.get(polis.size() - 1 ).flipFace(); + } + } + verts0.clear(); verts1.clear(); xCur = xEnd; yCur = yEnd; zCur = zEnd; sCur = topScale; + } + int halfv2 = verts2.size() / 2; + for(int i = 0; i < halfv2; i++){ + if(i >= seglimit && segl){ + TexturedVertex[] arr = new TexturedVertex[4]; float xpos = uStart + uOffset + (uCircle * 2f); + arr[0] = verts2.get(0).setTexturePosition(xpos, vStart + vOffset + vCircle); + arr[1] = verts3.get(0).setTexturePosition(xpos, vStart + vOffset + vCircle + vHeight); + arr[2] = verts3.get(halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle + vHeight); + arr[3] = verts2.get(halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle); + polis.add(new TexturedPolygon(arr)); + if(!dirFront) polis.get(polis.size() - 1 ).flipFace(); + arr = new TexturedVertex[4]; + arr[0] = verts2.get(seglimit).setTexturePosition(xpos, vStart + vOffset + vCircle + vHeight); + arr[1] = verts3.get(seglimit).setTexturePosition(xpos, vStart + vOffset + vCircle + vHeight + vHeight); + arr[2] = verts3.get(seglimit + halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle + vHeight + vHeight); + arr[3] = verts2.get(seglimit + halfv2).setTexturePosition(xpos + ((radius - radius2) * uScale), vStart + vOffset + vCircle + vHeight); + polis.add(new TexturedPolygon(arr)); + if(dirFront) polis.get(polis.size() - 1 ).flipFace(); + break; + } + if(i >= (halfv2 - 1)) break; + TexturedVertex[] arr = new TexturedVertex[4]; + if(!bools[2]){ + arr[0] = verts2.get(i + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle); + arr[1] = verts3.get(i + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle + vHeight); + arr[2] = verts3.get(i + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle + vHeight); + arr[3] = verts2.get(i + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle); + polis.add(new TexturedPolygon(arr)); + if(dirFront) polis.get(polis.size() - 1 ).flipFace(); + } + if(!bools[3]){ + arr = new TexturedVertex[4]; + arr[0] = verts2.get(i + halfv2 + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle + vHeight); + arr[1] = verts3.get(i + halfv2 + 0).setTexturePosition(uStart + uOffset + uWidth * (i + 0), vStart + vOffset + vCircle + vHeight + vHeight); + arr[2] = verts3.get(i + halfv2 + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle + vHeight + vHeight); + arr[3] = verts2.get(i + halfv2 + 1).setTexturePosition(uStart + uOffset + uWidth * (i + 1), vStart + vOffset + vCircle + vHeight); + polis.add(new TexturedPolygon(arr)); + if(!dirFront) polis.get(polis.size() - 1 ).flipFace(); + } + } + faces.addAll(polis); + return this; + } + + /** + * Instances a new FMT CylinderBuilder + */ + public CylinderBuilder newCylinderBuilder(){ + return new CylinderBuilder(this); + } + + /** + * Instances a new FMT BoxBuilder + */ + public BoxBuilder newBoxBuilder(){ + return new BoxBuilder(this); + } + + /** + * Adds a Waveform .obj file as a model. Model files use the entire texture file. + * @param file the location of the .obj file. The location is relative to the base directories, + * which are either resources/models or resources/mods/models. + */ + public ModelRendererTurbo addObj(String file){ + addModel(file, ModelPool.OBJ); + return this; + } + + public void addObjF(String file){ + try{ + addModelF(file, ModelPool.OBJ); + } + catch(IOException e) { + e.printStackTrace(); + } + } + + /** + * Adds model format support. Model files use the entire texture file. + * @param file the location of the model file. The location is relative to the base directories, + * which are either resources/models or resources/mods/models. + * @param modelFormat the class of the model format interpreter + */ + public void addModel(String file, Class modelFormat){ + ModelPoolEntry entry = ModelPool.addFile(file, modelFormat); + if(entry == null){ + return; + } + if(mirror){ + for (TexturedPolygon face : entry.faces) { + face.flipFace(); + } + } + faces.addAll(Arrays.asList(entry.faces)); + } + + public void addModelF(String file, Class modelFormat) throws IOException{ + ModelPoolEntry entry = ModelPool.addFileF(file, modelFormat); + if(entry == null){ + return; + } + if(mirror){ + for (TexturedPolygon face : entry.faces) { + face.flipFace(); + } + } + faces.addAll(Arrays.asList(entry.faces)); + } + + /** + * Sets a new position for the texture offset. + * @param x the x-coordinate of the texture start + * @param y the y-coordinate of the texture start + */ + public ModelRendererTurbo setTextureOffset(int x, int y){ + textureOffsetX = x; + textureOffsetY = y; + return this; + } + + /** + * Sets the position of the shape, relative to the model's origins. Note that changing + * the offsets will not change the pivot of the model. + * @param x the x-position of the shape + * @param y the y-position of the shape + * @param z the z-position of the shape + */ + public ModelRendererTurbo setPosition(float x, float y, float z){ + rotationPointX = x; + rotationPointY = y; + rotationPointZ = z; + return this; + } + + /** + * Sets the rotation point of the shape, relative to the model's origins. Note that changing + * the offsets will not change the pivot of the model. + * @param x the x-rotation point of the shape + * @param y the y-rotation point of the shape + * @param z the z-rotation point of the shape + */ + public ModelRendererTurbo setRotationPoint(float x, float y, float z){ + rotationPointX = x; + rotationPointY = y; + rotationPointZ = z; + return this; + } + /** + * + * Sets the rotation angles of the shape. + * @param x the x-rotation angle of the shape + * @param y the y-rotation angle of the shape + * @param z the z-rotation angle of the shape + */ + public ModelRendererTurbo setRotationAngle(float x, float y, float z){ + rotateAngleX = x; + rotateAngleY = y; + rotateAngleZ = z; + return this; + } + + /** + * Mirrors the model in any direction. + * @param x whether the model should be mirrored in the x-direction + * @param y whether the model should be mirrored in the y-direction + * @param z whether the model should be mirrored in the z-direction + */ + public void doMirror(boolean x, boolean y, boolean z){ + for(TexturedPolygon face : faces){ + List verts = face.vertices; + for(TexturedVertex vert : verts){ + vert.vector3F.addVector( + vert.vector3F.xCoord * (x ? -1 : 1), + vert.vector3F.xCoord * (y ? -1 : 1), + vert.vector3F.xCoord * (z ? -1 : 1)); + } + if(x^y^z){ + Collections.reverse(face.vertices); + } + } + } + + /** + * Sets whether the shape is mirrored or not. This has effect on the way the textures + * get displayed. When working with addSprite, addPixel and addObj, it will be ignored. + * @param isMirrored a boolean to define whether the shape is mirrored + */ + public void setMirrored(boolean isMirrored){ + mirror = isMirrored; + } + + + /** + * Clears the current shape. Since all shapes are stacked into one shape, you can't + * just replace a shape by overwriting the shape with another one. In this case you + * would need to clear the shape first. + */ + public void clear(){ + faces = new ArrayList<>(); + } + + + + public void render(){ + render(0.0625F); + } + + @Deprecated + //this is a lazy fix that should be replaced with the hide/show part tags when the models using it get reworked. + public void renderClean(){ + GL11.glPushMatrix(); + render(0.0625F); + GL11.glPopMatrix(); + } + + /** + * Renders the shape. + * @param scale the scale of the shape. Usually is 0.0625. + */ + public void render(float scale){ + if(!showModel){ + return; + } + if (ignoresLighting){ + Minecraft.getMinecraft().entityRenderer.disableLightmap(1D); + } + if(noCull){ + GL11.glDisable(GL11.GL_CULL_FACE); + } + if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F){ + GL11.glTranslatef(rotationPointX * scale, rotationPointY * scale, rotationPointZ * scale); + } + + if(rotateAngleY != 0.0F){ + GL11.glRotatef(rotateAngleY, 0.0F, 1.0F, 0.0F); + } + if(rotateAngleZ != 0.0F){ + GL11.glRotatef(rotateAngleZ, 0.0F, 0.0F, 1.0F); + } + if(rotateAngleX != 0.0F){ + GL11.glRotatef(rotateAngleX, 1.0F, 0.0F, 0.0F); + } + + for (TexturedPolygon poly : faces) { + Tessellator.getInstance().drawTexturedVertsWithNormal(poly, scale); + } + if(rotationPointX != 0.0F || rotationPointY != 0.0F || rotationPointZ != 0.0F){ + GL11.glTranslatef(-rotationPointX * scale, -rotationPointY * scale, -rotationPointZ * scale); + } + if(noCull){ + GL11.glEnable(GL11.GL_CULL_FACE); + } + if (ignoresLighting){ + Minecraft.getMinecraft().entityRenderer.enableLightmap(1D); + } + } + + + + + //ETERNAL: changed w/h/d to floats for better support of the custom render on the rails. + public ModelRendererTurbo addShapeBox(float x, float y, float z, float w, float h, float d, float scale, float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float x5, float y5, float z5, float x6, float y6, float z6, float x7, float y7, float z7){ + width=w;height=h;depth=d; + if(w==0){ + x-=0.005f; + w=0.005f; + } + if(h==0){ + y-=0.005f; + h=0.005f; + } + if(d==0) { + z -= 0.005f; + d=0.005f; + } + float f4 = x + w, f5 = y + h, f6 = z + d; + x -= scale; y -= scale; z -= scale; + f4 += scale; f5 += scale; f6 += scale; + if(mirror){ + float f7 = f4; f4 = x; x = f7; + } + + float[][] v = {{x - x0, y - y0, z - z0}, {f4 + x1, y - y1, z - z1},{f4 + x5, f5 + y5, z - z5}, {x - x4, f5 + y4, z - z4}, {x - x3, y - y3, f6 + z3}, {f4 + x2, y - y2, f6 + z2},{f4 + x6, f5 + y6, f6 + z6}, {x - x7, f5 + y7, f6 + z7}}; + + if(w==0.005f){ + w=0; + } + if(h==0.005f){ + h=0; + } + if(d==0.005f){ + d=0; + } + addRectShape(v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], w, h, d,null); + + return this; + } + + + public ModelRendererTurbo addShapeBox(float x, float y, float z, float w, float h, float d, float scale, float x0, float y0, float z0, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, float x4, float y4, float z4, float x5, float y5, float z5, float x6, float y6, float z6, float x7, float y7, float z7, boolean[] sides){ + float xw = x + w, yh = y + h, zd = z + d; x -= scale; y -= scale; z -= scale; xw += scale; yh += scale; zd += scale; + if(mirror){ float fl = xw; xw = x; x = fl; } + float[] v0 = {x - x0, y - y0, z - z0}, v1 = {xw + x1, y - y1, z - z1}, v2 = {xw + x5, yh + y5, z - z5}; + float[] v3 = {x - x4, yh + y4, z - z4}, v4 = {x - x3, y - y3, zd + z3}, v5 = {xw + x2, y - y2, zd + z2}; + float[] v6 = {xw + x6, yh + y6, zd + z6}, v7 = {x - x7, yh + y7, zd + z7}; + return addRectShape(v0, v1, v2, v3, v4, v5, v6, v7, w, h, d, sides); + } + + @Override + public String toString(){ + return (boxName==null?"unnamed model":boxName); + } + + + //name set for FMT compatibility. + public ModelRendererTurbo setName(String n){ + boxName=n; + return this; + } + + + //stub for FMT compatibility. + public ModelRendererTurbo setTextured(boolean b){ + return this; + } + + //stub for FMT compatibility. + public ModelRendererTurbo setLines(boolean b){ + return this; + } + +} \ No newline at end of file diff --git a/src/main/java/fexcraft/tmt/slim/README.md b/src/main/java/fexcraft/tmt/slim/README.md new file mode 100644 index 0000000000..6d7b1092e1 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/README.md @@ -0,0 +1,23 @@ + +Modified TMT from https://github.com/Fexcraft/FCL +Original branch version this was copied from: https://github.com/Fexcraft/FCL/tree/9331a66cda097e55e743f2590b3dc6cf1b78f137 +
+

Primary license:

+This version of TMT was updated, maintened, as well as extended for 1.8 and newer Minecraft versions by FEX___96 + + @author GaryCXJk, Ferdinand (FEX___96) + @license http://fexcraft.net/license?id=tmt + +
+

Eternal's notes and license:

+ + This version of TMT is heavily modified to fix some bugs in my own way, and attempt to improve performance overall. + - for performance reasons, the legacy render mode is used by default since we don't expect multiple textures to be used across the same model. + - The bones system has been fully removed and replaced with some minor support functionality for my static model animator. + - For performance and typesafe reasons PositionTransformVertex has been fully reworked to no longer extend or require the variables from PositionTextureVertex. + - For performance reasons TexturedPolygon has been fully reworked to no longer require TexturedQuad. + - ModelRendererTurbo no longer has reliance on minecraft's base model class. + - Because of the reworked classes mentioned above, and other performance reasons, Tessellator has been completley reworked from the ground up. + - public void copyTo(PositionTextureVertex[] verts, TexturedQuad[] quad) was removed since the new reworks make it fully obsolete. + + You are free to use any of my changes to this system in any way you want with no restrictions. \ No newline at end of file diff --git a/src/main/java/fexcraft/tmt/slim/Shape2D.java b/src/main/java/fexcraft/tmt/slim/Shape2D.java new file mode 100644 index 0000000000..2f46b8593e --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/Shape2D.java @@ -0,0 +1,119 @@ +package fexcraft.tmt.slim; + +import net.minecraft.util.MathHelper; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + + +public class Shape2D { + + public ArrayList coords; + + public Shape2D(){ + coords = new ArrayList(); + } + + public Shape2D(Coord2D[] coordArray){ + coords = new ArrayList(); + coords.addAll(Arrays.asList(coordArray)); + } + + public Shape2D(ArrayList coordList){ + coords = coordList; + } + + public Coord2D[] getCoordArray(){ + return (Coord2D[])coords.toArray(); + } + + public TexturedPolygon[] extrude(float x, float y, float z, float rotX, float rotY, float rotZ, float depth, int u, int v, float textureWidth, float textureHeight, int shapeTextureWidth, int shapeTextureHeight, int sideTextureWidth, int sideTextureHeight, float[] faceLengths){ + TexturedVertex[] verts = new TexturedVertex[coords.size() * 2]; + TexturedVertex[] vertsTop = new TexturedVertex[coords.size()]; + TexturedVertex[] vertsBottom = new TexturedVertex[coords.size()]; + TexturedPolygon[] poly = new TexturedPolygon[coords.size() + 2]; + Vec3f extrudeVector = new Vec3f(0, 0, depth); + + setVectorRotations(extrudeVector, rotX, rotY, rotZ); + + if(faceLengths != null && faceLengths.length < coords.size()){ + faceLengths = null; + } + float totalLength = 0; + for(int idx = 0; idx < coords.size(); idx++){ + Coord2D curCoord = coords.get(idx); + Coord2D nextCoord = coords.get((idx + 1) % coords.size()); + float texU1 = ((float)(curCoord.uCoord + u) / textureWidth); + float texU2 = ((float)(shapeTextureWidth * 2 - curCoord.uCoord + u) / textureWidth); + float texV = ((float)(curCoord.vCoord + v) / textureHeight); + Vec3f vecCoord = new Vec3f(curCoord.xCoord, curCoord.yCoord, 0); + setVectorRotations(vecCoord, rotX, rotY, rotZ); + verts[idx] = new TexturedVertex( + x + vecCoord.xCoord, + y + vecCoord.yCoord, + z + vecCoord.zCoord, texU1, texV); + verts[idx + coords.size()] = new TexturedVertex( + x + vecCoord.xCoord - extrudeVector.xCoord, + y + vecCoord.yCoord - extrudeVector.yCoord, + z + vecCoord.zCoord - extrudeVector.zCoord, texU2, texV); + vertsTop[idx] = new TexturedVertex(verts[idx].vector3F, verts[idx].textureX, verts[idx].textureY); + vertsBottom[coords.size() - idx - 1] = new TexturedVertex(verts[idx + coords.size()].vector3F, verts[idx + coords.size()].textureX, verts[idx + coords.size()].textureY); + if(faceLengths != null){ + totalLength+= faceLengths[idx]; + } + else{ + totalLength+= Math.sqrt(Math.pow(curCoord.xCoord - nextCoord.xCoord, 2) + Math.pow(curCoord.yCoord - nextCoord.yCoord, 2)); + } + } + poly[coords.size()] = new TexturedPolygon(Arrays.asList(vertsTop)); + poly[coords.size() + 1] = new TexturedPolygon(Arrays.asList(vertsBottom)); + float currentLengthPosition = totalLength; + + for(int idx = 0; idx < coords.size(); idx++){ + Coord2D nextCoord = coords.get((idx + 1) % coords.size()); + float currentLength = (float)Math.sqrt(Math.pow(coords.get(idx).xCoord - nextCoord.xCoord, 2) + Math.pow(coords.get(idx).yCoord - nextCoord.yCoord, 2)); + if(faceLengths != null){ + currentLength = faceLengths[faceLengths.length - idx - 1]; + } + float texU1 = ((((currentLengthPosition - currentLength) / totalLength) * (float)sideTextureWidth + u) / textureWidth); + float texU2 = (((currentLengthPosition / totalLength) * (float)sideTextureWidth + u) / textureWidth); + float texV1 = (((float)v + (float)shapeTextureHeight) / textureHeight); + float texV2 = (((float)v + (float)shapeTextureHeight + (float)sideTextureHeight) / textureHeight); + List polySide = new ArrayList<>(); + polySide.add(new TexturedVertex(verts[(idx + 1) % coords.size()].vector3F, texU1, texV1)); + polySide.add(new TexturedVertex(verts[coords.size() + ((idx + 1) % coords.size())].vector3F, texU1, texV2)); + polySide.add(new TexturedVertex(verts[coords.size() + idx].vector3F, texU2, texV2)); + polySide.add(new TexturedVertex(verts[idx].vector3F, texU2, texV1)); + poly[idx] = new TexturedPolygon(polySide); + currentLengthPosition -= currentLength; + } + return poly; + } + + protected Vec3f setVectorRotations(Vec3f extrudeVector, float xRot, float yRot, float zRot){ + float xC = MathHelper.cos(xRot); + float xS = MathHelper.sin(xRot); + float yC = MathHelper.cos(yRot); + float yS = MathHelper.sin(yRot); + float zC = MathHelper.cos(zRot); + float zS = MathHelper.sin(zRot); + + double xVec = extrudeVector.xCoord; + double yVec = extrudeVector.yCoord; + double zVec = extrudeVector.zCoord; + + // rotation around x + double xy = xC*yVec - xS*zVec; + double xz = xC*zVec + xS*yVec; + // rotation around y + double yz = yC*xz - yS*xVec; + double yx = yC*xVec + yS*xz; + // rotation around z + double zx = zC*yx - zS*xy; + double zy = zC*xy + zS*yx; + + return new Vec3f(zx, zy, yz); + } + +} \ No newline at end of file diff --git a/src/main/java/fexcraft/tmt/slim/Tessellator.java b/src/main/java/fexcraft/tmt/slim/Tessellator.java new file mode 100644 index 0000000000..e8ed7e8c84 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/Tessellator.java @@ -0,0 +1,92 @@ +package fexcraft.tmt.slim; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; + +/** +* @Author EternalBlueFlame +* +*/ +@SideOnly(Side.CLIENT) +public class Tessellator{ + + public static Tessellator INSTANCE = new Tessellator(); + + private static Float x, y, z; + + public static Tessellator getInstance(){ + return INSTANCE; + } + + //use this to reset and define the drawing mode + public void startDrawing(int mode){ + x=null;y=null;z=null; + GL11.glBegin(mode); + } + + public void draw(){ + GL11.glEnd(); + } + + public void addVertex(float i, float j, float k){ + if(x!=null){ + GL11.glVertex3f(i+x,j+y,k+z); + + } else { + GL11.glVertex3f(i,j,k); + } + } + + public void addVertexWithUV(float i, float j, float k, float u, float v){ + + GL11.glTexCoord2f(u,v); + if(x!=null){ + GL11.glVertex3f(i+x,j+y,k+z); + + } else { + GL11.glVertex3f(i,j,k); + } + } + + public static void setTranslation(float xOffset, float yOffset, float zOffset){ + x = xOffset; y = yOffset; z = zOffset; + } + + public static void addTranslation(float xOffset, float yOffset, float zOffset){ + x += xOffset; y += yOffset; z += zOffset; + } + + public static void bindTexture(ResourceLocation uri){ + TextureManager.bindTexture(uri); + } + + public void drawTexturedVertsWithNormal(TexturedPolygon polygon, float scale){ + GL11.glBegin(polygon.vertices.size()==4?GL11.GL_QUADS:polygon.vertices.size()==3?GL11.GL_TRIANGLES:GL11.GL_POLYGON); + + setNormal(polygon.vertices.get(0).vector3F, polygon.vertices.get(1).vector3F, polygon.vertices.get(2).vector3F); + + for (TexturedVertex vert : polygon.vertices) { + GL11.glTexCoord2f(vert.textureX, vert.textureY); + + if (x != null) { + GL11.glVertex3f((vert.vector3F.xCoord + x) * scale, (vert.vector3F.yCoord + y) * scale, (vert.vector3F.zCoord + z) * scale); + } else { + GL11.glVertex3f(vert.vector3F.xCoord * scale, vert.vector3F.yCoord * scale, vert.vector3F.zCoord * scale); + } + } + + GL11.glEnd(); + } + + + public static void setNormal(Vec3f vec0, Vec3f vec1, Vec3f vec2) { + Vec3f vec = new Vec3f(vec1.subtract(vec2)).crossProduct(vec1.subtract(vec0)).normalize(); + GL11.glNormal3f( + (byte)((vec.xCoord+90) * 127.0F), + (byte)(vec.yCoord * 127.0F), + (byte)(vec.zCoord * 127.0F)); + } + +} diff --git a/src/main/java/fexcraft/tmt/slim/TextureGroup.java b/src/main/java/fexcraft/tmt/slim/TextureGroup.java new file mode 100644 index 0000000000..09895f94c1 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/TextureGroup.java @@ -0,0 +1,37 @@ +package fexcraft.tmt.slim; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.texture.TextureManager; +import net.minecraft.util.ResourceLocation; + +import java.util.ArrayList; + +public class TextureGroup { + + public ArrayList poly; + public String texture; + + public TextureGroup(){ + poly = new ArrayList(); + texture = ""; + } + + public void addPoly(TexturedPolygon quad){ + poly.add(quad); + } + + public void loadTexture(){ + loadTexture(-1); + } + + public void loadTexture(int defaultTexture){ + if(!texture.equals("")){ + TextureManager renderengine = Minecraft.getMinecraft().renderEngine; + renderengine.bindTexture(new ResourceLocation("", texture)); + } + else if(defaultTexture > -1){ + Minecraft.getMinecraft().renderEngine.bindTexture(new ResourceLocation("", "")); + } + } + +} diff --git a/src/main/java/fexcraft/tmt/slim/TextureManager.java b/src/main/java/fexcraft/tmt/slim/TextureManager.java new file mode 100644 index 0000000000..ff14a749d8 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/TextureManager.java @@ -0,0 +1,531 @@ +package fexcraft.tmt.slim; + +import ebf.tim.utility.ClientUtil; +import ebf.tim.utility.DebugUtil; +import net.minecraft.block.Block; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.entity.RenderItem; +import net.minecraft.client.renderer.texture.*; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.EnumSkyBlock; +import net.minecraft.world.World; +import org.lwjgl.BufferUtils; +import org.lwjgl.opengl.GL11; +import train.client.core.ClientProxy; +import train.common.core.handlers.ConfigHandler; +import train.common.library.Info; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.FloatBuffer; +import java.util.*; +import java.util.List; + +import static org.lwjgl.opengl.GL11.*; + +public class TextureManager { + + + //public static ByteBuffer renderPixels = ByteBuffer.allocateDirect((4096*4096)*4); + private static int skyLight; + private static Set MCResourcePacks; + public static Map tmtBoundTextures = new HashMap<>(); + private static Integer currentKey; + + public static Map ingotColors = new HashMap<>(); + + + private static Map tmtMap = new HashMap<>(); + + private static ITextureObject object; + + /** + * custom texture binding method, generally same as vanilla, but possible to improve performance later. + * @param textureURI + */ + public static int bindTexture(ResourceLocation textureURI) { + if (textureURI == null){ + Minecraft.getMinecraft().getTextureManager().bindTexture(new ResourceLocation(Info.modID,"nullTrain")); + return 0; + } + //clean out the texture bind map when texturepacks are reloaded. + if(MCResourcePacks!= Minecraft.getMinecraft().getResourceManager().getResourceDomains()){ + MCResourcePacks= Minecraft.getMinecraft().getResourceManager().getResourceDomains(); + tmtMap=new HashMap<>(); + tmtBoundTextures = new HashMap<>(); + } + if(!ConfigHandler.FORCE_TEXTURE_BINDING) { + object = Minecraft.getMinecraft().getTextureManager().getTexture(textureURI); + if (object == null) { + object = new SimpleTexture(textureURI); + Minecraft.getMinecraft().getTextureManager().loadTexture(textureURI, object); + } + GL11.glBindTexture(GL_TEXTURE_2D, object.getGlTextureId()); + return object.getGlTextureId(); + } else { + Integer id; + if (!tmtMap.containsKey(textureURI)){ + object = Minecraft.getMinecraft().getTextureManager().getTexture(textureURI); + if (object == null) { + object = new SimpleTexture(textureURI); + Minecraft.getMinecraft().getTextureManager().loadTexture(textureURI, object); + } + id=object.getGlTextureId(); + tmtMap.put(textureURI, id); + } else { + id= tmtMap.get(textureURI); + } + if(GL11.glGetInteger(GL_TEXTURE_2D) !=id) { + GL11.glBindTexture(GL_TEXTURE_2D, id); + } + } + return -1; + } + + //most compilers should process this type of function faster than a normal typecast. + public static byte b(int i){return (byte) i;} + + public static boolean colorInRange(int r, int g, int b, int oldR, int oldG, int oldB){ + return oldR-r>-17 && oldR-r <17 && + oldG-g>-17 && oldG-g <17 && + oldB-b>-17 && oldB-b <17; + } + + + /**Lighting fix*/ + public static void adjustLightFixture(World world, int i, int j, int k) { + skyLight = world.getSkyBlockTypeBrightness(EnumSkyBlock.Block, i, j, k); + skyLight=world.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, i, j, k) << 20 | (skyLight<0?0:skyLight) << 4; + OpenGlHelper.setLightmapTextureCoords(OpenGlHelper.lightmapTexUnit, skyLight % 65536, skyLight * 0.00001525878f); + GL11.glColor4f(1, 1, 1, 1);//fixes alpha layering bugs with other mods that don't clear their GL cache + } + + private static FloatBuffer colorBuffer = GLAllocation.createDirectFloatBuffer(16); + + private static FloatBuffer setColorBuffer(float p_74521_0_, float p_74521_1_, float p_74521_2_, float p_74521_3_) + { + colorBuffer.clear(); + colorBuffer.put(p_74521_0_).put(p_74521_1_).put(p_74521_2_).put(p_74521_3_); + colorBuffer.flip(); + /** Float buffer used to set OpenGL material colors */ + return colorBuffer; + } + + public static void fixEntityLighting(){ + + GL11.glEnable(GL11.GL_LIGHTING); + GL11.glEnable(GL11.GL_LIGHT0); + GL11.glEnable(GL11.GL_LIGHT1); + GL11.glEnable(GL11.GL_COLOR_MATERIAL); + GL11.glColorMaterial(GL11.GL_FRONT_AND_BACK, GL11.GL_AMBIENT_AND_DIFFUSE); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_POSITION, setColorBuffer(0.16169041989141428f, 0.8084520874101966f, -0.5659164515496377f, 0.0f)); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_DIFFUSE, setColorBuffer(0.6F,0.6F,0.6F, 1.0F)); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_AMBIENT, setColorBuffer(0.0F, 0.0F, 0.0F, 1.0F)); + GL11.glLight(GL11.GL_LIGHT0, GL11.GL_SPECULAR, setColorBuffer(0.0F,0.0F,0.0F, 1.0F)); + GL11.glLight(GL11.GL_LIGHT1, GL11.GL_POSITION, setColorBuffer(-0.16169041989141428f, 0.8084520874101966f,0.5659164515496377f, 0.0f)); + GL11.glLight(GL11.GL_LIGHT1, GL11.GL_DIFFUSE, setColorBuffer(0.6F,0.6F,0.6F, 1.0F)); + GL11.glLight(GL11.GL_LIGHT1, GL11.GL_AMBIENT, setColorBuffer(0.0F, 0.0F, 0.0F, 1.0F)); + GL11.glLight(GL11.GL_LIGHT1, GL11.GL_SPECULAR, setColorBuffer(0.0F,0.0F,0.0F, 1.0F)); + GL11.glShadeModel(GL11.GL_FLAT); + GL11.glLightModel(GL11.GL_LIGHT_MODEL_AMBIENT, setColorBuffer(0.4F,0.4F,0.4F, 1.0F)); + + } + + + /** + * Ingot color textures + */ + public static void collectIngotColors() { + List Ores = new ArrayList<>();// = RecipeManager.getAcceptedRailItems(); + + int red, green, blue, divisor; + int[] rgb, colorBuff; + for (ItemStack s : Ores) { + if (s != null && s.getItem() != null) { + + red = 0; + green = 0; + blue = 0; + divisor = 0; + //this is less efficient than doing it directly, but if i promote the functionality for + // getting the array of bytes to something reuseable, it returns a blank spritez + colorBuff = renderItemViewport(s, 32); + for (int c : colorBuff) { + rgb = hexToargb(c); + red += rgb[3]; + green += rgb[1]; + blue += rgb[2]; + divisor++; + } + ingotColors.put(s, new int[]{red / divisor, blue / divisor, green / divisor}); + + } + } + } + + + public static TextureAtlasSprite bindBlockTextureFromSide(int side, ItemStack b){ + if (RenderBlocks.getInstance().hasOverrideBlockTexture()) { + return (TextureAtlasSprite)RenderBlocks.getInstance().overrideBlockTexture; + } + return (TextureAtlasSprite) RenderBlocks.getInstance().getBlockIconFromSideAndMetadata(Block.getBlockFromItem(b.getItem()), side,b.getItemDamage()); + //1.8.9+ version: + //IBlockState state = Block.getBlockFromItem(b.getItem()).getDefaultState(); + //Minecraft.getMinecraft().getBlockRendererDispatcher().getModelForState(state).getQuads(state,side,0l).get(0).getSprite() + } + + public static int[] hexTorgba(int hex){ + return new int[]{hex&0xFF, (hex>>8)&0xFF, (hex>>16)&0xFF, (hex>>24)&0xFF}; + } + public static int[] hexToargb(int hex) { + return new int[]{(hex >> 24) & 0xFF, hex & 0xFF, (hex >> 8) & 0xFF, (hex >> 16) & 0xFF}; + } + + public static int[] hexTorgb(int hex){ + return new int[]{hex&0xFF, (hex>>8)&0xFF, (hex>>16)&0xFF}; + } + + + + public static int[] postProcessColor(int newColor, int r, int g, int b){ + int[] ret =hexTorgb(newColor); + + ret[0] += ret[0]-b; + ret[1] += ret[1]-g; + ret[2] += ret[2]-r; + return ret; + } + + + + + public static boolean textureExists(ResourceLocation textureURI){ + + object = Minecraft.getMinecraft().getTextureManager().getTexture(textureURI); + if (object == null) { + object = new SimpleTexture(textureURI); + Minecraft.getMinecraft().getTextureManager().loadTexture(textureURI, object); + } + return object.getGlTextureId()!=TextureUtil.missingTexture.getGlTextureId(); + } + + + + + public static void bindTexture(ResourceLocation textureURI, int[] skinColorsFrom, int[] skinColorsTo, List colorsFrom, List colorsTo){ + //clean out the texture bind map when texturepacks are reloaded. + if (MCResourcePacks != Minecraft.getMinecraft().getResourceManager().getResourceDomains()) { + MCResourcePacks = Minecraft.getMinecraft().getResourceManager().getResourceDomains(); + tmtMap = new HashMap<>(); + tmtBoundTextures = new HashMap<>(); + } + + GL11.glEnable(GL_TEXTURE_2D); + if (!tmtBoundTextures.containsKey(getID(textureURI, skinColorsFrom, skinColorsTo, colorsFrom, colorsTo, false))) { + if (createAWT(textureURI, skinColorsFrom, skinColorsTo, colorsFrom, colorsTo) && + new File(getID(textureURI,skinColorsFrom, skinColorsTo, colorsFrom,colorsTo,true)).exists()) { + try { + BufferedImage image = ImageIO.read(new File(getID(textureURI, skinColorsFrom, skinColorsTo, colorsFrom, colorsTo, true))); + + currentKey = tmtBoundTextures.put(getID(textureURI, skinColorsFrom, skinColorsTo, colorsFrom, colorsTo, false), + Minecraft.getMinecraft().getTextureManager().getTexture( + Minecraft.getMinecraft().getTextureManager().getDynamicTextureLocation( + getID(textureURI, skinColorsFrom, skinColorsTo, colorsFrom, colorsTo, true), + new DynamicTexture(image))).getGlTextureId()); + } catch (IOException exception) { + DebugUtil.println("AWT FAILED"); + exception.printStackTrace(); + } + } + } else { + currentKey = tmtBoundTextures.get(getID(textureURI, skinColorsFrom, skinColorsTo, colorsFrom, colorsTo, false)); + } + + //if for some reason the texture couldn't be written to I/O, which should never be an issue. + if (currentKey == null) { + bindTexture(textureURI); + } else { + if (GL11.glGetInteger(GL_TEXTURE_2D) != currentKey) { + GL11.glBindTexture(GL_TEXTURE_2D, currentKey); + } + } + + } + + + + public static boolean createAWT(ResourceLocation textureURI, int[] skinColorsFrom, int[] skinColorsTo, List colorsFrom, List colorsTo){ + int GLtexture = bindTexture(textureURI); + if(GLtexture==-1){ + return true; + } + + //get image data from the currently bound image + int width =glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH); + int height =glGetTexLevelParameteri(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT); + if(width*height<4){ + return false; + } + + ByteBuffer buffer = BufferUtils.createByteBuffer(width * height * 4); + + GL11.glGetTexImage(GL_TEXTURE_2D, 0, GL11.GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + //create a buffered image and push the data to it + BufferedImage skin = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + int i,r,g,b,a, y,ii; + int[] col; + + for (int x = 0; x < width; x++) { + for (y = 0; y < height; y++) { + + i = (x + (width * y)) * 4; + r = buffer.get(i) & 0xff; + g = buffer.get(i + 1) & 0xff; + b = buffer.get(i + 2) & 0xff; + a = buffer.get(i + 3) & 0xff; + if(a<10){ + skin.setRGB(x,y,0x00000000); + continue; + } + + //recolor from skin + if(skinColorsFrom!=null&&skinColorsFrom.length>0){ + for (ii=0;ii0) { + for (ii=0;ii colorsFrom, List colorsTo, boolean isFile){ + StringBuilder filePath = new StringBuilder(); + if(isFile) { + filePath.append(ClientProxy.configDirectory); + filePath.append("/TrainsInMotion/TextureCache/"); + filePath.append(resourceLocation(textureURI)); + filePath.append("/"); + if(skinColorsFrom!=null && skinColorsTo!=null && skinColorsFrom.length>0 && skinColorsTo.length>0) { + for (Integer i : skinColorsFrom) { + filePath.append(Integer.toHexString(i)); + } + filePath.append("_"); + for (Integer i : skinColorsTo) { + filePath.append(Integer.toHexString(i)); + } + filePath.append("+"); + } + if(colorsFrom==null || colorsTo==null || colorsFrom.size()+colorsTo.size()==0){ + filePath.append("000_000"); + } else { + for (Integer i : colorsFrom) { + filePath.append(Integer.toHexString(i)); + } + filePath.append("_"); + for (Integer i : colorsTo) { + filePath.append(Integer.toHexString(i)); + } + } + filePath.append(".png"); + } else { + filePath.append(resourceLocation(textureURI)); + filePath.append("."); + if(skinColorsFrom!=null && skinColorsTo!=null && skinColorsFrom.length>0 && skinColorsTo.length>0) { + for (Integer i : skinColorsFrom) { + filePath.append(Integer.toHexString(i)); + } + filePath.append("_"); + for (Integer i : skinColorsTo) { + filePath.append(Integer.toHexString(i)); + } + if(colorsFrom!=null && colorsTo!=null && colorsFrom.size()+colorsTo.size()>1) { + filePath.append("+"); + } + } + if(colorsFrom!=null && colorsTo!=null && colorsFrom.size()+colorsTo.size()>1){ + for (Integer i : colorsFrom) { + filePath.append(Integer.toHexString(i)); + } + for (Integer i : colorsTo) { + filePath.append(Integer.toHexString(i)); + } + } + } + return filePath.toString(); + } + + private static String resourceLocation(ResourceLocation res){ + return (res.getResourceDomain() + "/" + +res.getResourcePath(). + substring(0, res.getResourcePath().lastIndexOf("."))); + } + + /* + gets an item texture as an array of pixels, with 0x00000000 as "empty" pixels + scale is based off 32. so for example entering 64 will be double scale. + */ + public static int[] renderItemViewport(ItemStack stack, int scale) { + int[] pixels = new int[scale*scale]; + GL11.glPushMatrix(); + + GL11.glTranslatef(0,(Minecraft.getMinecraft().displayHeight*0.5f)-(scale*0.5f),500); + + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glColor4f(0.75f,0.75f,0.75f,1); + ClientUtil.drawTexturedRect(0,0,0,0,scale,scale); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glColor4f(1,1,1,1); + + GL11.glScalef(scale/32f,scale/32f,scale/32f); + RenderHelper.enableGUIStandardItemLighting(); + new RenderItem().renderItemAndEffectIntoGUI(Minecraft.getMinecraft().fontRenderer, + Minecraft.getMinecraft().getTextureManager(),stack, 0, 0); + ByteBuffer buffer = BufferUtils.createByteBuffer(scale * scale * 4); + GL11.glReadPixels(0, 0, scale, scale, GL11.GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + int i,r,g,b; + + for(int x=0; x=254 && g>=254 && b>=254){ + pixels[(x + ((scale * (scale-1)) - (scale * y)))] = 0xffffffff; + } else { + pixels[(x + ((scale * (scale-1)) - (scale * y)))] = (255 << 24) | (r << 16) | (g << 8) | b; + } + } + } + RenderHelper.disableStandardItemLighting(); + GL11.glPopMatrix(); + return pixels; + } + + /* + Writes an item texture to a specified file, good for making icons and stuff. + clone of the above method with slight alterations for having a different use case + be sure to check if Traincraft.proxy.isClient() or a similar check, is true before running. + scale is based off 32. so for example entering 64 will be double scale. + */ + public static void renderItemViewportToFile(ItemStack stack, ResourceLocation path, int scale) { + if (!new File(ClientProxy.configDirectory + "/TrainsInMotion/TextureCache/" + + resourceLocation(path)).exists()) { + new File(ClientProxy.configDirectory + "/TrainsInMotion/TextureCache/" + + resourceLocation(path)).mkdirs(); + } + GL11.glPushMatrix(); + + GL11.glTranslatef(0,(Minecraft.getMinecraft().displayHeight*0.5f)-(scale*0.5f),500); + + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glColor4f(1,1,1,1); + ClientUtil.drawTexturedRect(0,0,0,0,scale,scale); + GL11.glEnable(GL11.GL_TEXTURE_2D); + + GL11.glScalef(scale/32f,scale/32f,scale/32f); + RenderHelper.enableGUIStandardItemLighting(); + new RenderItem().renderItemAndEffectIntoGUI(Minecraft.getMinecraft().fontRenderer, + Minecraft.getMinecraft().getTextureManager(),stack, 0, 0); + new RenderItem().renderItemOverlayIntoGUI(Minecraft.getMinecraft().fontRenderer, + Minecraft.getMinecraft().getTextureManager(), stack, 0, 0, ""); + ByteBuffer buffer = BufferUtils.createByteBuffer(scale * scale * 4); + GL11.glReadPixels(0, 0, scale, scale, GL11.GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + try { + if(!new File(TextureManager.getID(new ResourceLocation(Info.modID,"testexture.png"), + null, null, null, null, true)).exists()){ + + int i,r,g,b,a; + + //create a buffered image and push the data to it + BufferedImage skin = new BufferedImage(64, 64, BufferedImage.TYPE_INT_ARGB); + + for(int x=0; x=254 && g>=254 && b>=254){ + a=0; + } else { + a=255; + } + + //y is flipped for some gods forsaken reason. + // so we need to count Y backwards from the end of the array. + if(a==0){ + skin.setRGB(x, scale - y, 0x00000000); + } else { + skin.setRGB(x, scale - y,(a << 24) | (r << 16) | (g << 8) | b); + } + } + } + + try { + ImageIO.write(skin, "PNG", new File(TextureManager.getID(new ResourceLocation(Info.modID,"testexture.png"), + null, null, null, null, true))); + } catch (IOException e) { + e.printStackTrace(); + } + } + } catch (Exception e){ + e.printStackTrace(); + } + + } +} diff --git a/src/main/java/fexcraft/tmt/slim/TexturedPolygon.java b/src/main/java/fexcraft/tmt/slim/TexturedPolygon.java new file mode 100644 index 0000000000..c182d8f9f6 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/TexturedPolygon.java @@ -0,0 +1,31 @@ +package fexcraft.tmt.slim; + + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + + +public class TexturedPolygon { + + + public List vertices; + + public TexturedPolygon(List apositionTexturevertex){ + vertices = apositionTexturevertex; + } + public TexturedPolygon(TexturedVertex[] apositionTexturevertex){ + vertices = Arrays.asList(apositionTexturevertex); + } + + public void flipFace(){ + Collections.reverse(vertices); + } + + public TexturedPolygon flipFace(boolean check){ + if(check){Collections.reverse(vertices);} + return this; + } + + +} \ No newline at end of file diff --git a/src/main/java/fexcraft/tmt/slim/TexturedVertex.java b/src/main/java/fexcraft/tmt/slim/TexturedVertex.java new file mode 100644 index 0000000000..537056ee28 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/TexturedVertex.java @@ -0,0 +1,46 @@ +package fexcraft.tmt.slim; + +import net.minecraft.client.model.PositionTextureVertex; + +public class TexturedVertex { + + public Vec3f vector3F; + public float textureX; + public float textureY; + + public TexturedVertex(float x, float y, float z, float u, float v){ + this(new Vec3f(x, y, z), u, v); + } + + public TexturedVertex(float x, float y, float z){ + this(new Vec3f(x, y, z), 0,0); + } + + public TexturedVertex(TexturedVertex vert){ + this(vert.vector3F, vert.textureX, vert.textureY); + } + + @Deprecated + public TexturedVertex(PositionTextureVertex vertex, float u, float v){ + vector3F = new Vec3f(vertex.vector3D); + textureX = u; + textureY = v; + } + + public TexturedVertex(Vec3f vector, float u, float v){ + vector3F = new Vec3f(vector.xCoord, vector.yCoord, vector.zCoord); + textureX = u; + textureY = v; + } + + public TexturedVertex setTexturePosition(float p_78240_1_, float p_78240_2_) { + return new TexturedVertex(vector3F, p_78240_1_, p_78240_2_); + } + + public void setUV(float u, float v){ + textureX=u; + textureY=v; + } + + +} diff --git a/src/main/java/fexcraft/tmt/slim/Vec3d.java b/src/main/java/fexcraft/tmt/slim/Vec3d.java new file mode 100644 index 0000000000..5241b5d7e7 --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/Vec3d.java @@ -0,0 +1,45 @@ +package fexcraft.tmt.slim; + + +import net.minecraft.util.Vec3; + +/** + * @author EternalBlueFlame + *

Vector 3d

+ * this is intended to replicate the Vec3d from minecraft 1.8+ + * mostly it just makes handling vector 3's simpler. + */ +public class Vec3d { + + public double xCoord=0,yCoord=0,zCoord=0; + + public Vec3d(double x, double y, double z){ + xCoord=x;yCoord=y;zCoord=z; + } + + public Vec3d(Vec3 vec){this(vec.xCoord, vec.yCoord, vec.zCoord);} + + public void add(Vec3d vec2){ + xCoord += vec2.xCoord; + yCoord += vec2.yCoord; + zCoord += vec2.zCoord; + } + + public Vec3d subtract(Vec3d vec2){ + return new Vec3d(xCoord-vec2.xCoord,yCoord-vec2.yCoord,zCoord-vec2.zCoord); + } + + public Vec3d subtractVector(double x, double y, double z){ + xCoord-=x;yCoord-=y;zCoord-=z; + return this; + } + + public Vec3d crossProduct(double value){ + return new Vec3d(xCoord*value,yCoord*value,zCoord*value); + } + + public Vec3d addVector(double x, double y, double z){ + xCoord+=x;yCoord+=y;zCoord+=z; + return this; + } +} diff --git a/src/main/java/fexcraft/tmt/slim/Vec3f.java b/src/main/java/fexcraft/tmt/slim/Vec3f.java new file mode 100644 index 0000000000..903a23e69a --- /dev/null +++ b/src/main/java/fexcraft/tmt/slim/Vec3f.java @@ -0,0 +1,246 @@ +package fexcraft.tmt.slim; + +import net.minecraft.util.Vec3; +import org.lwjgl.util.vector.Matrix4f; +import org.lwjgl.util.vector.Vector3f; + +import java.io.Serializable; + +import static ebf.tim.utility.CommonUtil.radianF; + +/** + * basically the same as Vec3D, but a float. Usually used for storing rotations. + * @author Ferdinand + */ + + +public class Vec3f implements Serializable { + + public float xCoord; + public float yCoord; + public float zCoord; + + public Vec3f(){ + xCoord = 0; + yCoord = 0; + zCoord = 0; + } + + public Vec3f(double xVec, double yVec, double zVec) { + this((float)xVec, (float)yVec, (float)zVec); + } + + public Vec3f(Vec3 v){ + xCoord = (float)v.xCoord; + yCoord = (float)v.yCoord; + zCoord= (float)v.zCoord; + } + public Vec3f(Vec3f v){ + xCoord = v.xCoord; + yCoord = v.yCoord; + zCoord= v.zCoord; + } + + public Vec3f(float f, float g, float h){ + xCoord = f; + yCoord = g; + zCoord = h; + } + + public Vec3f(float[] v){ + xCoord = v[0]; + yCoord = v[1]; + zCoord= v[2]; + } + + public Vec3f crossProduct(Vec3f p_72431_1_) { + return new Vec3f(this.yCoord * p_72431_1_.zCoord - this.zCoord * p_72431_1_.yCoord, this.zCoord * p_72431_1_.xCoord - this.xCoord * p_72431_1_.zCoord, this.xCoord * p_72431_1_.yCoord - this.yCoord * p_72431_1_.xCoord); + } + + public Vec3f scale(float scale){ + return new Vec3f(this.xCoord * scale, this.yCoord * scale, this.zCoord * scale); + } + + public Vec3f scale(float scaleX, float scaleY, float scaleZ){ + return new Vec3f(this.xCoord * scaleX, this.yCoord * scaleY, this.zCoord * scaleZ); + } + + public Vec3f subtract(float x, float y, float z){ + return this.addVector(-x, -y, -z); + } + + public Vec3f add(Vec3f vec){ + return this.addVector(vec.xCoord, vec.yCoord, vec.zCoord); + } + + //todo: this probably broke everything, undo + public Vec3f addVector(float x, float y, float z){ + xCoord+=x; + yCoord+=y; + zCoord+=z; + return this; + } + + public Vec3f addVector(double x, double y, double z){ + xCoord+=x; + yCoord+=y; + zCoord+=z; + return this; + } + + public Vec3f subtract(Vec3f vec){ + return new Vec3f(xCoord-vec.xCoord, + yCoord-vec.yCoord, + zCoord-vec.zCoord); + } + + + public Vec3f normalize(){ + double d0 = Math.sqrt(this.xCoord * this.xCoord + this.yCoord * this.yCoord + this.zCoord * this.zCoord); + return d0 < 1.0E-4D ? new Vec3f() : new Vec3f(this.xCoord / d0, this.yCoord / d0, this.zCoord / d0); + } + + public float dotProduct(Vec3f vec){ + return this.xCoord * vec.xCoord + this.yCoord * vec.yCoord + this.zCoord * vec.zCoord; + } + + + public float dot2D(Vec3f other){ + return this.xCoord * other.xCoord + this.zCoord * other.zCoord; + } + + public static Vec3f direction(float... arr){ + double l = length(arr[0], arr[1], arr[2]); return new Vec3f(arr[0] / l, arr[1] / l, arr[2] / l); + } + + public static Vec3f direction(Vec3f vec){ + double l = length(vec.xCoord, vec.yCoord, vec.zCoord); return new Vec3f(vec.xCoord / l, vec.yCoord / l, vec.zCoord / l); + } + + //based on fvtm rail entity stuff + public Vec3f distance(Vec3f dest, float am){ + Vec3f vec = new Vec3f((xCoord + dest.xCoord) * 0.5, (yCoord + dest.yCoord) * 0.5, (zCoord + dest.zCoord) * 0.5); + vec = direction(vec.xCoord - xCoord, vec.yCoord - yCoord, vec.zCoord - zCoord); + return new Vec3f(xCoord + (vec.xCoord * am), yCoord + (vec.yCoord * am), zCoord + (vec.zCoord * am)); + } + + public Vec3f distance(Vec3f dest, double am){ + Vec3f vec = new Vec3f((xCoord + dest.xCoord) * 0.5, (yCoord + dest.yCoord) * 0.5, (zCoord + dest.zCoord) * 0.5); + vec = direction(vec.xCoord - xCoord, vec.yCoord - yCoord, vec.zCoord - zCoord); + return new Vec3f(xCoord + (vec.xCoord * am), yCoord + (vec.yCoord * am), zCoord + (vec.zCoord * am)); + } + public Vec3f distance(float[] dest, float am){ + Vec3f vec = new Vec3f((xCoord + dest[0]) * 0.5, (yCoord + dest[1]) * 0.5, (zCoord + dest[2]) * 0.5); + vec = direction(vec.xCoord - xCoord, vec.yCoord - yCoord, vec.zCoord - zCoord); + return new Vec3f(xCoord + (vec.xCoord * am), yCoord + (vec.yCoord * am), zCoord + (vec.zCoord * am)); + } + + public double length(){ + return Math.sqrt(xCoord * xCoord + yCoord * yCoord + zCoord * zCoord); + } + + + public double length2d(){ + return Math.sqrt(xCoord * xCoord + zCoord * zCoord); + } + + public static double length(float... arr){ + return Math.sqrt(arr[0] * arr[0] + arr[1] * arr[1] + arr[2] * arr[2]); + } + + public static double length(Vec3f vec){ + return Math.sqrt(vec.xCoord * vec.xCoord + vec.yCoord * vec.yCoord + vec.zCoord * vec.zCoord); + } + + public boolean equals(Object obj){ + if(this == obj){ + return true; + } + else if(!(obj instanceof Vec3f)){ + return false; + } + else{ + Vec3f vec3d = (Vec3f)obj; + return Float.compare(vec3d.xCoord, this.xCoord) != 0 ? false : (Float.compare(vec3d.yCoord, this.yCoord) != 0 ? false : Float.compare(vec3d.zCoord, this.zCoord) == 0); + } + } + + public int hashCode(){ + long j = Float.floatToIntBits(this.xCoord); + int i = (int)(j ^ j >>> 32); + j = Float.floatToIntBits(this.yCoord); + i = 31 * i + (int)(j ^ j >>> 32); + j = Float.floatToIntBits(this.zCoord); + i = 31 * i + (int)(j ^ j >>> 32); + return i; + } + + public float distance(Vec3f vec){ + float d0 = vec.xCoord - this.xCoord; + float d1 = vec.yCoord - this.yCoord; + float d2 = vec.zCoord - this.zCoord; + return (float)Math.sqrt(d0 * d0 + d1 * d1 + d2 * d2); + } + + public float distance2d(Vec3f vec){ + return Math.abs(this.xCoord - vec.xCoord)+Math.abs(this.zCoord - vec.zCoord); + } + + @Override + public String toString(){ + return String.format("Vec3f[ %s, %s, %s ]", xCoord, yCoord, zCoord); + } + + + //this could be moved to vec3f + public Vec3f getRelativeVector(Vec3f vec){ + Matrix4f mat = new Matrix4f(); + mat.m00 = vec.xCoord; mat.m10 = vec.yCoord; mat.m20 = vec.zCoord; + Matrix4f.rotate(zCoord * 3.14159265F / 180, new Vector3f(1F, 0F, 0F), mat, mat); + Matrix4f.rotate(yCoord * 3.14159265F / 180, new Vector3f(0F, 0F, 1F), mat, mat); + Matrix4f.rotate(xCoord * 3.14159265F / 180, new Vector3f(0F, 1F, 0F), mat, mat); + return new Vec3f(mat.m00, mat.m10, mat.m20); + } + + public Vec3f rotatePoint(float pitch, float yaw, float roll) { + float cos,sin,x=xCoord,y=yCoord,z=zCoord; + //rotate pitch + if (pitch != 0.0F) { + cos = (float)Math.cos(pitch*radianF); + sin = (float)Math.sin(pitch*radianF); + + xCoord = (y * sin) + (x * cos); + yCoord = (y * cos) - (x * sin); + } + //rotate yaw + if (yaw != 0.0F) { + cos = (float)Math.cos(yaw*radianF); + sin = (float)Math.sin(yaw*radianF); + + xCoord = (x * cos) - (z * sin); + zCoord = (x * sin) + (z * cos); + } + //rotate roll + if (roll != 0.0F) { + cos = (float)Math.cos(roll*radianF); + sin = (float)Math.sin(roll*radianF); + + yCoord = (z * cos) - (y * sin); + zCoord = (z * sin) + (y * cos); + } + return this; + } + + public Vec3f rotateOnYaw(float yaw) { + float cos,sin,x=xCoord,z=zCoord; + //rotate yaw + if (yaw != 0.0F) { + cos = (float)Math.cos(yaw*radianF); + sin = (float)Math.sin(yaw*radianF); + + xCoord = (x * cos) - (z * sin); + zCoord = (x * sin) + (z * cos); + } + return this; + } +} diff --git a/src/main/java/train/client/core/ClientProxy.java b/src/main/java/train/client/core/ClientProxy.java index 5c8bfecbef..79a49c7156 100644 --- a/src/main/java/train/client/core/ClientProxy.java +++ b/src/main/java/train/client/core/ClientProxy.java @@ -75,6 +75,11 @@ public static boolean isPumpkin() { return (cal.get(Calendar.MONTH) == Calendar.OCTOBER || cal.get(Calendar.MONTH) == Calendar.NOVEMBER && cal.get(Calendar.DATE) < 15); } + @Override + public boolean isClient(){ + return true; + } + @Override public void throwAlphaException() { throw new AlphaExpiredException(); diff --git a/src/main/java/train/client/gui/GuiButtonRecipeSearch.java b/src/main/java/train/client/gui/GuiButtonRecipeSearch.java new file mode 100644 index 0000000000..7003976b9a --- /dev/null +++ b/src/main/java/train/client/gui/GuiButtonRecipeSearch.java @@ -0,0 +1,84 @@ +package train.client.gui; + +import cpw.mods.fml.relauncher.Side; +import cpw.mods.fml.relauncher.SideOnly; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.opengl.GL11; +import train.common.library.Info; + +/** + * @author 02skaplan + * Class for buttons used for search functionality in recipe book. + */ +@SideOnly(Side.CLIENT) +class GuiButtonRecipeSearch extends GuiButton { + enum Type { + PREVIOUSRESULT, + NEXTRESULT, + SEARCH + } + enum Texture { + ACTIVE, + INACTIVE + } + /** + * if the button has to be drawn drawButton is more than just draw, it makes the button exists or not too + */ + public boolean showButton; + private Type type; + /** + * Starting x-value on texture. + */ + private int u; + /** + * Starting y-value on texture. + */ + private final int v = 14; + + public GuiButtonRecipeSearch(int buttonID, int x, int y, int xSize, int ySize, Type type) { + super(buttonID, x, y, xSize, ySize, ""); + this.setType(type, Texture.INACTIVE); + } + + /** + * Draws this button to the screen. + */ + @Override + public void drawButton(Minecraft mc, int par2, int par3) { + if (this.visible && showButton) { + if (type == Type.SEARCH) { + if (par2 >= this.xPosition && par3 >= this.yPosition && par2 < this.xPosition + this.width && par3 < this.yPosition + this.height) + this.setType(Type.SEARCH, Texture.ACTIVE); + else + this.setType(Type.SEARCH, Texture.INACTIVE); + } + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation, Info.bookPrefix + "searchbar.png")); + this.drawTexturedModalRect(this.xPosition, this.yPosition, u, v, 10, 10); + } + } + public void setType(Type type, Texture texture) { + this.type = type; + if (type == Type.PREVIOUSRESULT) { + if (texture == Texture.ACTIVE) { + this.u = 0; + } else { + this.u = 20; + } + } else if (type == Type.NEXTRESULT) { + if (texture == Texture.ACTIVE) { + this.u = 10; + } else { + this.u = 30; + } + } else { + if (texture == Texture.ACTIVE) { + this.u = 50; + } else { + this.u = 40; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/train/client/gui/GuiRecipeBook.java b/src/main/java/train/client/gui/GuiRecipeBook.java index 38ab4ddb6a..8824effa65 100644 --- a/src/main/java/train/client/gui/GuiRecipeBook.java +++ b/src/main/java/train/client/gui/GuiRecipeBook.java @@ -4,6 +4,7 @@ import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.renderer.RenderHelper; import net.minecraft.client.renderer.entity.RenderItem; import net.minecraft.entity.player.EntityPlayer; @@ -25,8 +26,9 @@ import train.common.recipes.ShapedTrainRecipes; import train.common.recipes.ShapelessTrainRecipe; -import java.util.ArrayList; -import java.util.List; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; @SideOnly(Side.CLIENT) public class GuiRecipeBook extends GuiScreen { @@ -40,23 +42,31 @@ public class GuiRecipeBook extends GuiScreen { * Update ticks since the gui was opened */ private final int bookImageWidth = 206; + private final int bookImageHeight = 200; public static int bookTotalPages = 2; private int currPage; private int currRecipe; - public ArrayList leftPage = new ArrayList(); - public ArrayList leftPageImage = new ArrayList(); - public ArrayList leftPageItemStacks = new ArrayList(); - public ArrayList rightPage = new ArrayList(); - public ArrayList rightPageImage = new ArrayList(); - public ArrayList rightPageItemStacks = new ArrayList(); - private List recipeListWB = null; - private List recipeList = null; - - private GuiButtonNextPage buttonRead; - private GuiButtonNextPage buttonNextPage; - private GuiButtonNextPage buttonPreviousPage; - private GuiButtonNextPage buttonBack; - private final RenderItem renderItem = new RenderItem(); + private int searchResultsPosition = 0; + List resultIndexList = new ArrayList<>(); + public ArrayList leftPage = new ArrayList(); + public ArrayList leftPageImage = new ArrayList(); + public ArrayList leftPageItemStacks = new ArrayList(); + public ArrayList rightPage = new ArrayList(); + public ArrayList rightPageImage = new ArrayList(); + public ArrayList rightPageItemStacks = new ArrayList(); + private List recipeListWB =null; + private List recipeList=null; + private final TreeMap> recipeIndexMap = new TreeMap<>(); + + private GuiButtonNextPage buttonRead; + private GuiButtonNextPage buttonNextPage; + private GuiButtonNextPage buttonPreviousPage; + private GuiButtonNextPage buttonBack; + private GuiButtonRecipeSearch buttonSearchPrevious; + private GuiButtonRecipeSearch buttonSearchNext; + private GuiButtonRecipeSearch buttonSearch; + private GuiTextField searchBar; + private final RenderItem renderItem = new RenderItem(); public GuiRecipeBook(EntityPlayer par1EntityPlayer, ItemStack par2ItemStack) { this.editingPlayer = par1EntityPlayer; @@ -278,103 +288,107 @@ public GuiRecipeBook(EntityPlayer par1EntityPlayer, ItemStack par2ItemStack) { } }); - addPage("Making diesel:\nDiesel is made in a distillation tower using petroleum or oil sands found in the world.\nInsert petroleum in the top slot and fuel in the bottom slot, also try reed.\nIt will cook into liquid diesel and give you plastic with a random chance depending on the input.\nTo get diesel into canisters, you must first craft them using plastic. Then put an empty one in the top right slot.", "", "right", new ArrayList() { - { - add(new StackToDraw(new ItemStack(BlockIDs.distilIdle.block), 20, 16)); - add(new StackToDraw(new ItemStack(BlockIDs.distilActive.block), 150, 40)); - add(new StackToDraw(new ItemStack(BlockIDs.oreTC.block, 1, 1), 150, 20)); - add(new StackToDraw(new ItemStack(Items.coal), 150, 60)); - add(new StackToDraw(new ItemStack(ItemIDs.diesel.item), 167, 40)); - add(new StackToDraw(new ItemStack(ItemIDs.rawPlastic.item), 167, 60)); - } - }); - addPage("Special pull I: \nYou can attach two locomotives together.\n\nTo do that: shift+click the locomotive you want to PULL with a stake in your hand. Then fuel it and wait until it heats up.\n\nNow put both locomotives in attaching mode. Then move attach them by moving one locomotive towards the other.", "", "left", new ArrayList() { - { - add(new StackToDraw(new ItemStack(ItemIDs.minecartLocoBR80_DB.item), 20, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.stake.item), 170, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartCabooseWork.item), 40, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartTankWagon_DB.item), 60, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartFlatCartRail_DB.item), 80, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 100, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 120, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 140, 165)); - } - }); - addPage("Special pull II: \nLocomotives have two states: 'Can pull' and 'Can be pulled'.\n'Can pull' means that the locomotive is able to pull any attach cart. But it can't be pulled.\n'Can be pulled' means that the locomotive behaves like a cart and can be pulled by another locomotive (which is in 'can pull' state). Attached locomotives share power.", "", "right", new ArrayList() { - { - add(new StackToDraw(new ItemStack(ItemIDs.minecartLoco3.item), 20, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.stake.item), 170, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 40, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 60, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 80, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 100, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 120, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 140, 165)); - } - }); - addPage("Armors I: \nThere are several armors in the mod.\nThree of them are mostly skins (engineer, ticket man and driver) with same caracteristics as leather armor.\nOn the contrary, the composite suit is an armor with special capabilities and strong resistance and durability.\nSee next page for details.", "", "left", new ArrayList() { - { - add(new StackToDraw(new ItemStack(ItemIDs.hat.item), 20, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.hat_ticketMan_paintable.item), 170, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.hat_driver_paintable.item), 40, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.jacket_driver_paintable.item), 90, 165)); - add(new StackToDraw(new ItemStack(ItemIDs.pants_driver_paintable.item), 140, 165)); - } - }); - addPage("Armors II: \nThe helmet cures poisons, helps you breathe under water, and gives night vision in dark places (not when riding an entity)\nThe chest regen half a heart every 5s.\nThe pants protect you against fire damage.\nThe boots absorb fall damage.\n" + "Ticket man, driver and composite armors are paintable (in train workbench)", "", "right", new ArrayList() { - { - add(new StackToDraw(new ItemStack(ItemIDs.helmet_suit_paintable.item), 20, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.reinforcedPlates.item), 170, 16)); - } - }); - addPage("Generators:\nThere are three generators in the mod.\nWater wheel, Wind mill, and Diesel Generator are RF generators. Water wheel has to be placed beside flowing water. Plug kinesis pipes to the sides.\nWind mill will produce various energy amount depending on wind strength.\nFill the Diesel Generator with diesel, power it with redstone, plug some kinesis pipes.\n", "", "left", new ArrayList() { - { - add(new StackToDraw(new ItemStack(BlockIDs.windMill.block, 1, 4), 20, 16)); - add(new StackToDraw(new ItemStack(BlockIDs.waterWheel.block, 1, 4), 170, 16)); - } - }); - addPage("Villager\n\nTraincraft adds a new villager and a train station to village generation.\n\nThe villager will trade all traincraft items with you upon various prices.\n", "", "right", new ArrayList() { - { - add(new StackToDraw(new ItemStack(ItemIDs.jacket_driver_paintable.item, 1, 4), 20, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.hat_driver_paintable.item, 1, 4), 170, 16)); - } - }); - addPage("Known bugs:\n- Sharp turns are not supported (close 180 turns)\n- When coming backwards from the Curve of a switch too slow Switchstate can be false\n- Jukebox Volume incorrect after rejoin/restart\n- Don't use 4 TC Slopes in a row!\n- TC Slopes won't work above about y=160 ", "", "left", new ArrayList() { - { - add(new StackToDraw(new ItemStack(Items.skull, 1, 4), 20, 16)); - add(new StackToDraw(new ItemStack(Items.skull, 1, 4), 170, 16)); - } - }); - - addPage("Advice:\nDue to the bounding box issues, carts have to be attached and PULLED. Don't try to push\n\nRailcraft pull system has been deactivated on Traincraft loco. Use TC's system. \n", "", "right", new ArrayList() { - { - add(new StackToDraw(new ItemStack(ItemIDs.minecartTankWagon_DB.item), 20, 16)); - add(new StackToDraw(new ItemStack(BlockIDs.oreTC.block), 170, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartCaboose3.item), 40, 155)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWellcar.item), 60, 155)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartOpenWagon.item), 80, 155)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartStockCar.item), 100, 155)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartOpenWagon.item), 120, 155)); - add(new StackToDraw(new ItemStack(ItemIDs.minecartBR_E69.item), 140, 155)); - } - }); - - addPage("On the following pages you will find all the train workbench recipes and assembly table recipes.\nIt is however strongly suggested to try to discover the recipes by yourself...\n\nWe hope you will enjoy the mod!\n\nSpitfire4466 and MrBrutal", "", "left", new ArrayList() { - { - add(new StackToDraw(new ItemStack(BlockIDs.trainWorkbench.block), 20, 16)); - add(new StackToDraw(new ItemStack(ItemIDs.hat.item), 40, 155)); - add(new StackToDraw(new ItemStack(ItemIDs.jacket.item), 90, 155)); - add(new StackToDraw(new ItemStack(ItemIDs.overalls.item), 140, 155)); - } - }); - addPage("this page was intentionally left blank, as a joke.", "", "right", null); - if (recipeListWB == null || recipeListWB.size() < 1) { - recipeListWB = RecipeBookHandler.workbenchListCleaner(TrainCraftingManager.getInstance().getRecipeList()); - recipeList = RecipeBookHandler.assemblyListCleaner(TierRecipeManager.getInstance().getRecipeList()); - } - if (rightPage != null && recipeList != null && recipeListWB != null) - bookTotalPages = this.rightPage.size() + (recipeList.size() / 2) + (recipeListWB.size() / 2); - } + addPage("Making diesel:\nDiesel is made in a distillation tower using petroleum or oil sands found in the world.\nInsert petroleum in the top slot and fuel in the bottom slot, also try reed.\nIt will cook into liquid diesel and give you plastic with a random chance depending on the input.\nTo get diesel into canisters, you must first craft them using plastic. Then put an empty one in the top right slot.", "", "right", new ArrayList() { + { + add(new StackToDraw(new ItemStack(BlockIDs.distilIdle.block), 20, 16)); + add(new StackToDraw(new ItemStack(BlockIDs.distilActive.block), 150, 40)); + add(new StackToDraw(new ItemStack(BlockIDs.oreTC.block, 1, 1), 150, 20)); + add(new StackToDraw(new ItemStack(Items.coal), 150, 60)); + add(new StackToDraw(new ItemStack(ItemIDs.diesel.item), 167, 40)); + add(new StackToDraw(new ItemStack(ItemIDs.rawPlastic.item), 167, 60)); + } + }); + addPage("Special pull I: \nYou can attach two locomotives together.\n\nTo do that: shift+click the locomotive you want to PULL with a stake in your hand. Then fuel it and wait until it heats up.\n\nNow put both locomotives in attaching mode. Then move attach them by moving one locomotive towards the other.", "", "left", new ArrayList() { + { + add(new StackToDraw(new ItemStack(ItemIDs.minecartLocoBR80_DB.item), 20, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.stake.item), 170, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartCabooseWork.item), 40, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartTankWagon_DB.item), 60, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartFlatCartRail_DB.item), 80, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 100, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 120, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 140, 165)); + } + }); + addPage("Special pull II: \nLocomotives have two states: 'Can pull' and 'Can be pulled'.\n'Can pull' means that the locomotive is able to pull any attach cart. But it can't be pulled.\n'Can be pulled' means that the locomotive behaves like a cart and can be pulled by another locomotive (which is in 'can pull' state). Attached locomotives share power.", "", "right", new ArrayList() { + { + add(new StackToDraw(new ItemStack(ItemIDs.minecartLoco3.item), 20, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.stake.item), 170, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 40, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 60, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 80, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 100, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWagon_DB.item), 120, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartCD742.item), 140, 165)); + } + }); + addPage("Armors I: \nThere are several armors in the mod.\nThree of them are mostly skins (engineer, ticket man and driver) with same caracteristics as leather armor.\nOn the contrary, the composite suit is an armor with special capabilities and strong resistance and durability.\nSee next page for details.", "", "left", new ArrayList() { + { + add(new StackToDraw(new ItemStack(ItemIDs.hat.item), 20, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.hat_ticketMan_paintable.item), 170, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.hat_driver_paintable.item), 40, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.jacket_driver_paintable.item), 90, 165)); + add(new StackToDraw(new ItemStack(ItemIDs.pants_driver_paintable.item), 140, 165)); + } + }); + addPage("Armors II: \nThe helmet cures poisons, helps you breathe under water, and gives night vision in dark places (not when riding an entity)\nThe chest regen half a heart every 5s.\nThe pants protect you against fire damage.\nThe boots absorb fall damage.\n"+ + "Ticket man, driver and composite armors are paintable (in train workbench)", "", "right", new ArrayList() { + { + add(new StackToDraw(new ItemStack(ItemIDs.helmet_suit_paintable.item), 20, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.reinforcedPlates.item), 170, 16)); + } + }); + addPage("Generators:\nThere are three generators in the mod.\nWater wheel, Wind mill, and Diesel Generator are RF generators. Water wheel has to be placed beside flowing water. Plug kinesis pipes to the sides.\nWind mill will produce various energy amount depending on wind strength.\nFill the Diesel Generator with diesel, power it with redstone, plug some kinesis pipes.\n","","left",new ArrayList() { + { + add(new StackToDraw(new ItemStack(BlockIDs.windMill.block, 1, 4), 20, 16)); + add(new StackToDraw(new ItemStack(BlockIDs.waterWheel.block, 1, 4), 170, 16)); + } + }); + addPage("Villager\n\nTraincraft adds a new villager and a train station to village generation.\n\nThe villager will trade all traincraft items with you upon various prices.\n","","right",new ArrayList() { + { + add(new StackToDraw(new ItemStack(ItemIDs.jacket_driver_paintable.item, 1, 4), 20, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.hat_driver_paintable.item, 1, 4), 170, 16)); + } + }); + addPage("Known bugs:\n- Sharp turns are not supported (close 180 turns)\n- When coming backwards from the Curve of a switch too slow Switchstate can be false\n- Jukebox Volume incorrect after rejoin/restart\n- Don't use 4 TC Slopes in a row!\n- TC Slopes won't work above about y=160 ", + "", "left", new ArrayList() { + { + add(new StackToDraw(new ItemStack(Items.skull, 1, 4), 20, 16)); + add(new StackToDraw(new ItemStack(Items.skull, 1, 4), 170, 16)); + } + }); + + addPage("Advice:\nDue to the bounding box issues, carts have to be attached and PULLED. Don't try to push\n\nRailcraft pull system has been deactivated on Traincraft loco. Use TC's system. \n","","right",new ArrayList() { + { + add(new StackToDraw(new ItemStack(ItemIDs.minecartTankWagon_DB.item), 20, 16)); + add(new StackToDraw(new ItemStack(BlockIDs.oreTC.block), 170, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartCaboose3.item), 40, 155)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartFreightWellcar.item), 60, 155)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartOpenWagon.item), 80, 155)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartStockCar.item), 100, 155)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartOpenWagon.item), 120, 155)); + add(new StackToDraw(new ItemStack(ItemIDs.minecartBR_E69.item), 140, 155)); + } + }); + + addPage("On the following pages you will find all the train workbench recipes and assembly table recipes.\nIt is however strongly suggested to try to discover the recipes by yourself...\n\nWe hope you will enjoy the mod!\n\nSpitfire4466 and MrBrutal", "", "left", new ArrayList() { + { + add(new StackToDraw(new ItemStack(BlockIDs.trainWorkbench.block), 20, 16)); + add(new StackToDraw(new ItemStack(ItemIDs.hat.item), 40, 155)); + add(new StackToDraw(new ItemStack(ItemIDs.jacket.item), 90, 155)); + add(new StackToDraw(new ItemStack(ItemIDs.overalls.item), 140, 155)); + } + }); + addPage("this page was intentionally left blank, as a joke.","","right",null); + if(recipeListWB==null || recipeListWB.size()<1){ + recipeListWB= RecipeBookHandler.workbenchListCleaner(TrainCraftingManager.getInstance().getRecipeList()); + recipeList = RecipeBookHandler.assemblyListCleaner(TierRecipeManager.getInstance().getRecipeList()); + } + if (rightPage != null && recipeList != null && recipeListWB != null) + bookTotalPages = this.rightPage.size() + (recipeList.size() / 2) + (recipeListWB.size() / 2); + // Initialize recipe map for searching. + initializeRecipeSearchMap(); + } public static class StackToDraw { private final ItemStack stack; @@ -421,92 +435,140 @@ private void addPage(String text, String image, String side, ArrayList 0 && this.currPage < bookTotalPages - 1); - this.buttonNextPage.showButton = (this.currPage > 0 && this.currPage < bookTotalPages - 1); - this.buttonPreviousPage.visible = this.currPage > 0; - this.buttonPreviousPage.showButton = this.currPage > 0; - } - - /** - * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e). - */ - @Override - protected void actionPerformed(GuiButton par1GuiButton) { - if (!par1GuiButton.enabled) { + this.searchBar.setEnabled(true); + this.searchBar.setVisible(false); + this.buttonBack.visible = (this.currPage == bookTotalPages-1); + this.buttonBack.showButton = true; + this.buttonRead.visible = (this.currPage == 0); + this.buttonRead.showButton = false; + this.buttonNextPage.visible = (this.currPage > 0 && this.currPage < bookTotalPages - 1); + this.buttonNextPage.showButton = (this.currPage > 0 && this.currPage < bookTotalPages - 1); + this.buttonPreviousPage.visible = this.currPage > 0; + this.buttonPreviousPage.showButton = this.currPage > 0; + this.buttonSearchPrevious.visible = this.currPage > 0; + this.buttonSearchPrevious.showButton = this.currPage > 0; + this.buttonSearchNext.visible = this.currPage > 0; + this.buttonSearchNext.showButton = this.currPage > 0; + this.buttonSearch.visible = this.currPage > 0; + this.buttonSearch.showButton = this.currPage > 0; + } + + /** + * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e). + */ + @Override + protected void actionPerformed(GuiButton par1GuiButton) { + if (par1GuiButton.enabled) { + switch (par1GuiButton.id) { + case 1: + if (this.currPage < bookTotalPages - 1) { + ++this.currPage; + this.currRecipe += 2; + } + break; + case 2: + if (this.currPage > 0) { + --this.currPage; + this.currRecipe -= 2; + } + break; + case 3: + if (this.currPage == 0) { + ++this.currPage; + this.currRecipe += 2; + } + break; + case 4: + if (this.currPage == bookTotalPages - 1) { + this.currPage = 0; + this.currRecipe = 0; + } + break; + case 5: // Previous search result. + if (searchResultsPosition - 1 >= 0) { + searchResultsPosition--; + runSearch(); + } + break; + case 6: // Next search result. + if (searchResultsPosition < resultIndexList.size() - 1) { + searchResultsPosition++; + runSearch(); + } + break; + case 7: // Search button (if hitting RETURN is too complicated for you). + runSearch(); + break; + } + this.updateButtons(); + } else { return; } + } - if (par1GuiButton.id == 1) { - if (this.currPage < bookTotalPages - 1) { - ++this.currPage; - this.currRecipe += 2; - } - } else if (par1GuiButton.id == 2) { - if (this.currPage > 0) { - --this.currPage; - this.currRecipe -= 2; - } - } else if (par1GuiButton.id == 3) { - if (this.currPage == 0) { - ++this.currPage; - this.currRecipe += 2; - } - } else if (par1GuiButton.id == 4) { - if (this.currPage == bookTotalPages - 1) { - this.currPage = 0; - this.currRecipe = 0; - } - } - this.updateButtons(); - } - - /** - * Draws the screen and all the components in it. - */ @Override - public void drawScreen(int par1, int par2, float par3) { - String pageIndic; - int var9; - int var5 = (this.width) / 2; - int bookImageHeight = 200; + public void mouseClicked(int x, int y, int par3) { + super.mouseClicked(x, y, par3); + searchBar.mouseClicked(x, y, par3); + } + + /** + * Draws the screen and all the components in it. + */ + @Override + public void drawScreen(int par1, int par2, float par3) { + String pageIndic; + int var9; + int var5 = (this.width) / 2; + int bookImageHeight = 200; int var6 = (this.height) / 2 - bookImageHeight / 2; - - if (this.currPage > 0) { - //GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation, Info.bookPrefix + "bookright.png")); - this.drawTexturedModalRect(var5, var6, 0, 0, this.bookImageWidth, bookImageHeight + 20); - //GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); - mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation, Info.bookPrefix + "bookleft.png")); - var5 -= this.bookImageWidth; - this.drawTexturedModalRect(var5, var6, 256 - this.bookImageWidth, 0, this.bookImageWidth, bookImageHeight); - } else { - mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation, Info.bookPrefix + "bookcover.png")); - this.drawTexturedModalRect(var5 - 55, var6 - 15, 0, 0, 256, 256); - } + int SEARCH_BOX_X = var5; + int SEARCH_BOX_Y = var6 - 12; + int SEARCH_BOX_TEXT_MAX_WIDTH = 136; + + if (this.currPage > 0) { + //GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation,Info.bookPrefix + "bookright.png")); + this.drawTexturedModalRect(var5, var6, 0, 0, this.bookImageWidth, this.bookImageHeight + 20); + mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation,Info.bookPrefix + "searchbar.png")); + this.drawTexturedModalRect(SEARCH_BOX_X, SEARCH_BOX_Y, 0, 0, 192, 13); + mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation,Info.bookPrefix + "bookleft.png")); + var5 -= this.bookImageWidth; + this.drawTexturedModalRect(var5, var6, 256 - this.bookImageWidth, 0, this.bookImageWidth, this.bookImageHeight); + this.searchBar.drawTextBox(); + } + else { + mc.renderEngine.bindTexture(new ResourceLocation(Info.resourceLocation,Info.bookPrefix + "bookcover.png")); + this.drawTexturedModalRect(var5 - 55, var6 - 15, 0, 0, 256, 256); + } pageIndic = String.format(StatCollector.translateToLocal("book.pageIndicator"), new Object[]{this.currPage + 1, this.bookTotalPages}); - var9 = this.fontRendererObj.getStringWidth(pageIndic); - if (this.currPage > 0) { - this.fontRendererObj.drawString(pageIndic, var5 - var9 + this.bookImageWidth - 44, var6 + 7, 0); - } - super.drawScreen(par1, par2, par3); + var9 = this.fontRendererObj.getStringWidth(pageIndic); + if (this.currPage > 0) { + this.fontRendererObj.drawString(pageIndic, var5 - var9 + this.bookImageWidth - 44, var6 + 7, 0); + this.fontRendererObj.drawString(fontRendererObj.trimStringToWidth(searchBar.getText(), SEARCH_BOX_TEXT_MAX_WIDTH), SEARCH_BOX_X + 21, SEARCH_BOX_Y + 3, 0); + } + super.drawScreen(par1, par2, par3); if (this.currPage < rightPage.size()) { this.fontRendererObj.drawSplitString(leftPage.get(this.currPage), var5 + 36, var6 + 16 + 16, 140, 0); @@ -535,12 +597,14 @@ public void drawScreen(int par1, int par2, float par3) { if (this.currPage > rightPage.size() - 1) { //System.out.println((rightPage.size()*2) -1); int page = this.currRecipe - (rightPage.size() * 2) + 1; + // Drawing the non-train recipes... if (!(page > recipeListWB.size() - 1)) { drawWorkBenchBackground(recipeListWB, var5, var6, 0, var9, "right"); drawWorkBenchBackground(recipeListWB, var5, var6, 0, var9, "left"); RenderHelper.enableGUIStandardItemLighting(); drawWorkBenchRecipe(recipeListWB, var5, var6, page - 1, var9, "right"); drawWorkBenchRecipe(recipeListWB, var5, var6, page, var9, "left"); + // Drawing the train recipes... } else if ((page - recipeListWB.size()) >= 0 && (page - recipeListWB.size()) < recipeList.size() && recipeList.get(page - recipeListWB.size()) != null) { drawAssemblyBackground(recipeList, var5 - 125, var6 - 33, page - recipeListWB.size(), var9, "right"); drawAssemblyBackground(recipeList, var5 - 50, var6 - 33, page - recipeListWB.size() - 1, var9, "left"); @@ -631,7 +695,8 @@ private void drawWorkBenchRecipe(List recipeList, int var5, int var6, int page, if (itemOutput != null && itemOutput.getItem() != null) { renderItem.renderItemIntoGUI(this.fontRendererObj, this.mc.renderEngine, itemOutput, var5 + 145 + offset, var6 + 85); - this.fontRendererObj.drawString(itemOutput.getItem().getItemStackDisplayName(itemOutput), var5 + 20 + offset, var6 + 40, 0); + // Draw name of recipe. Highlight in green if it contains the search query. + this.fontRendererObj.drawString(itemOutput.getItem().getItemStackDisplayName(itemOutput), var5 + 20 + offset, var6 + 40, (!searchBar.getText().isEmpty() && itemOutput.getItem().getItemStackDisplayName(itemOutput).toLowerCase().contains(searchBar.getText().toLowerCase())) ? 0x21d12d : 0); } if (itemOutput != null) { @@ -653,7 +718,7 @@ private void drawAssemblyRecipe(List recipeList, int var5, int var6, return; } int tier = recipeList.get(page).getTier(); - + List itemList = recipeList.get(page).getInput(); int offset = 0; if (side.equals("right")) offset = 271; @@ -754,13 +819,17 @@ private void drawAssemblyRecipe(List recipeList, int var5, int var6, name = output.getDisplayName(); } + // Handle highlighting of names based on search results. + boolean drawColorHighlightFlag = name.toLowerCase().contains(searchBar.getText().toLowerCase()); + + // Draw item names and tiers. if (side.equals("left")) { this.fontRendererObj.drawString("Tier: " + tier, var5 - var9 + this.bookImageWidth - 56, var6 + 40, 0); - this.fontRendererObj.drawString(name, var5 - var9 + this.bookImageWidth - 55, var6 + 56, 0xffffff); + this.fontRendererObj.drawString(fontRendererObj.trimStringToWidth(name, 150), var5 - var9 + this.bookImageWidth - 45, var6 + 56, (!searchBar.getText().isEmpty() && drawColorHighlightFlag) ? 0x21d12d : 0xffffff); } if (side.equals("right")) { - this.fontRendererObj.drawString(name, var5 - var9 + this.bookImageWidth + 215, var6 + 56, 0xffffff); + this.fontRendererObj.drawString(fontRendererObj.trimStringToWidth(name, 150), var5 - var9 + this.bookImageWidth + 225, var6 + 56, (!searchBar.getText().isEmpty() && drawColorHighlightFlag) ? 0x21d12d : 0xffffff); this.fontRendererObj.drawString("Tier: " + tier, var5 - var9 + this.bookImageWidth + 338, var6 + 40, 0); } GL11.glDisable(32826); @@ -775,15 +844,166 @@ public void onGuiClosed() { super.onGuiClosed(); } - @Override - public boolean doesGuiPauseGame() { - return false; - } - - @Override - protected void keyTyped(char par1, int par2) { - if (par2 == 1 || par2 == this.mc.gameSettings.keyBindInventory.getKeyCode()) { - this.mc.thePlayer.closeScreen(); - } - } + @Override + public boolean doesGuiPauseGame() { + return false; + } + + /** + * Handles key presses for the search bar. + */ + @Override + protected void keyTyped(char eventChar, int eventKey) { + if (eventKey == 1 || eventChar == '\u007F') { // If ESC or CTRL+Backspace... + if (searchBar.getText().isEmpty()) { // If search query is empty, exit. + this.mc.thePlayer.closeScreen(); + } else { // If there is a search query, clear it. + searchBar.setText(""); + resetSearch(); + } + } + if (eventChar == '\r') { // If character is return... + if (!searchBar.getText().isEmpty()) { + if (Pattern.compile(":\\d+").matcher(searchBar.getText()).find()) { + int newPage = Integer.parseInt(searchBar.getText().substring(1)) - 1; + if (newPage > 0 && newPage < bookTotalPages) { + this.currPage = newPage; + this.currRecipe = this.currPage * 2; + searchBar.setText(""); + resetSearch(); + } + this.updateButtons(); + } else { + runSearch(); + } + } + } else { // If character is not a backspace... + this.searchBar.textboxKeyTyped(eventChar, eventKey); + resetSearch(); + } + } + + /** + * @author 02skaplan + * If search has not been completed, this method runs search with given searchQuery. + * If search has been completed, this method advances the search page and increments searchResultsPosition. + * This method also handles highlighting and darkening GUI search buttons. + */ + public void runSearch() { + if (resultIndexList.isEmpty()) { // If we need to search for the query... + for (Map.Entry> mapEntry : recipeMapSearch(recipeIndexMap, searchBar.getText().toLowerCase()).entrySet()) { + for (int value : mapEntry.getValue()) { + if (!resultIndexList.contains(((value / 2) + rightPage.size()))) + resultIndexList.add(((value / 2) + rightPage.size())); + } + } + } + if (!resultIndexList.isEmpty() && searchResultsPosition < resultIndexList.size()) { // If the search is complete, display and increment result. + if (searchResultsPosition == resultIndexList.size() - 1) + this.buttonSearchNext.setType(GuiButtonRecipeSearch.Type.NEXTRESULT, GuiButtonRecipeSearch.Texture.INACTIVE); + else + this.buttonSearchNext.setType(GuiButtonRecipeSearch.Type.NEXTRESULT, GuiButtonRecipeSearch.Texture.ACTIVE); + if (searchResultsPosition - 1 < 0) + this.buttonSearchPrevious.setType(GuiButtonRecipeSearch.Type.PREVIOUSRESULT, GuiButtonRecipeSearch.Texture.INACTIVE); + else + this.buttonSearchPrevious.setType(GuiButtonRecipeSearch.Type.PREVIOUSRESULT, GuiButtonRecipeSearch.Texture.ACTIVE); + this.currPage = resultIndexList.get(searchResultsPosition); + this.currRecipe = this.currPage * 2; + this.updateButtons(); + } + } + + /** + * @author 02skaplan + */ + public void resetSearch() { + searchResultsPosition = 0; + resultIndexList = new ArrayList<>(); + this.buttonSearchPrevious.setType(GuiButtonRecipeSearch.Type.PREVIOUSRESULT, GuiButtonRecipeSearch.Texture.INACTIVE); + this.buttonSearchNext.setType(GuiButtonRecipeSearch.Type.NEXTRESULT, GuiButtonRecipeSearch.Texture.INACTIVE); + } + + public SortedMap> recipeMapSearch(TreeMap> fullMap, String searchQuery) { + // Thank you, PaĆ­lo Ebermann, for this TreeMap partial search algorithm! + if (!searchQuery.isEmpty()) { + char nextLetter = (char) (searchQuery.charAt(searchQuery.length() - 1) + 1); + String end = searchQuery.substring(0, searchQuery.length() - 1) + nextLetter; + return fullMap.subMap(searchQuery, end); + } + return fullMap; + } + + /** + * @author 02skaplan + * Initializes the recipe map used for searching through book. Loops through both sets of recipe lists + * and adds each full name and each space-delimited term to the map using an ArrayList of ints to store result + * pages for each term. + */ + private void initializeRecipeSearchMap() { + assert recipeListWB != null; + assert recipeList != null; + String name; + for (int i = 0; i < recipeListWB.size(); i++) { + name = ((ShapedTrainRecipes) recipeListWB.get(i)).getRecipeOutput().getDisplayName().toLowerCase(); + addToRecipeSearchMap(name, i); + } + for (int i = 0; i < recipeList.size(); i++) { + name = recipeList.get(i).getOutput().getDisplayName().toLowerCase(); + addToRecipeSearchMap(name, i + recipeListWB.size()); + } + } + + /** + * @author 02skaplan + * Adds a given name and asscociated terms to the recipe search map. + * If term is more than one word long, this adds each space-delimited element to the map for easier searching. + * If term is surrounded by [] or (), this removes the enclousure to allow for easier searching. + * @param name Localized name of recipe to add to search map. + * @param index Index of recipe within recipe book. + */ + private void addToRecipeSearchMap(String name, int index) { + String[] nameSplit; + ArrayList indexList; + // Regex pattern to capture groups surrounded by [] or (). + Pattern removeEnclosurePattern = Pattern.compile("[\\[|\\(](.+)[\\)|\\]]"); + Matcher matcher; + + // Add raw name to map. + if (!recipeIndexMap.containsKey(name)) { + indexList = new ArrayList<>(); + indexList.add(index); + recipeIndexMap.put(name, indexList); + } + // Add each part of split name to map. + nameSplit = name.split(" "); + for (String term : nameSplit) { + // If the term is surrounded by [] or (), remove before adding to make searching easier. + matcher = removeEnclosurePattern.matcher(term); + if (matcher.find()) { + if (recipeIndexMap.containsKey(matcher.group(1))) { + indexList = recipeIndexMap.get(matcher.group(1)); + if (!indexList.contains(index)) { + indexList.add(index); + recipeIndexMap.put(matcher.group(1), indexList); + } + } else { + indexList = new ArrayList<>(); + indexList.add(index); + recipeIndexMap.put(matcher.group(1), indexList); + } + } + // Add raw split name if not exists in map. + if (recipeIndexMap.containsKey(term)) { + indexList = recipeIndexMap.get(term); + if (!indexList.contains(index)) { + indexList.add(index); + recipeIndexMap.put(term, indexList); + } + } else { + indexList = new ArrayList<>(); + indexList.add(index); + recipeIndexMap.put(term, indexList); + } + } + } } \ No newline at end of file diff --git a/src/main/java/train/common/Traincraft.java b/src/main/java/train/common/Traincraft.java index 870f6a2a85..2fb7bf17f2 100644 --- a/src/main/java/train/common/Traincraft.java +++ b/src/main/java/train/common/Traincraft.java @@ -113,6 +113,7 @@ public void preInit(FMLPreInitializationEvent event) { configDirectory = event.getModConfigurationDirectory(); ConfigHandler.init(new File(event.getModConfigurationDirectory(), Info.modName + ".cfg")); + proxy.configDirectory = event.getModConfigurationDirectory().getAbsolutePath(); /* Register the KeyBinding Handler */ proxy.registerKeyBindingHandler(); diff --git a/src/main/java/train/common/api/EntityRollingStock.java b/src/main/java/train/common/api/EntityRollingStock.java index cb5b503452..f7a0e69912 100644 --- a/src/main/java/train/common/api/EntityRollingStock.java +++ b/src/main/java/train/common/api/EntityRollingStock.java @@ -54,12 +54,10 @@ import train.common.items.ItemTCRail.TrackTypes; import train.common.items.ItemWrench; import train.common.library.BlockIDs; -import train.common.library.EnumTrains; import train.common.tile.TileTCRail; import train.common.tile.TileTCRailGag; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import static train.common.core.util.TraincraftUtil.degrees; @@ -1897,23 +1895,26 @@ public void applyEntityCollision(Entity par1Entity) { } double d2 = d0 * d0 + d1 * d1; - if ((par1Entity instanceof AbstractTrains && d2 <= ((AbstractTrains) par1Entity).getLinkageDistance((EntityMinecart) par1Entity) * 0.7 && d2 >= 9.999999747378752E-5D) || (par1Entity instanceof EntityBogie && ((EntityBogie) par1Entity).entityMainTrain != null && d2 <= ((EntityBogie) par1Entity).entityMainTrain.getLinkageDistance((EntityMinecart) par1Entity) * 0.7 && d2 >= 9.999999747378752E-5D) || (!(par1Entity instanceof AbstractTrains) && d2 >= 9.999999747378752E-5D))// >= 9.999999747378752E-5D) - { - d2 = MathHelper.sqrt_double(d2); - if (d0 != 0) { - d0 /= d2; - } else { - d2 = 0; - } - if (d1 != 0) { - d1 /= d2; - } else { - d2 = 0; - } - - if (d2 > 1.0D) { - d2 = 1.0D; - } + if ((par1Entity instanceof AbstractTrains && d2 <= ((AbstractTrains) par1Entity).getLinkageDistance((EntityMinecart) par1Entity) * 0.7 && d2 >= 9.999999747378752E-5D) || (par1Entity instanceof EntityBogie && ((EntityBogie) par1Entity).entityMainTrain != null && d2 <= ((EntityBogie) par1Entity).entityMainTrain.getLinkageDistance((EntityMinecart) par1Entity) * 0.7 && d2 >= 9.999999747378752E-5D) || (!(par1Entity instanceof AbstractTrains) && d2 >= 9.999999747378752E-5D))// >= 9.999999747378752E-5D) + { + d2 = MathHelper.sqrt_double(d2); + double d2Clone = d2; + if (d0 != 0) { + d0 /= d2; + } else { + d2=0; + } + if (d1 != 0) { + d1 /= d2Clone; + } else { + d2Clone = 0; + } + if (d2 != d2Clone && d2 != 0) { + d2 = d2Clone; + } + if (d2 > 1.0D) { + d2 = 1.0D; + } d0 *= d2; d1 *= d2; diff --git a/src/main/java/train/common/api/LiquidTank.java b/src/main/java/train/common/api/LiquidTank.java index 0e556f0433..d384f0e3f2 100644 --- a/src/main/java/train/common/api/LiquidTank.java +++ b/src/main/java/train/common/api/LiquidTank.java @@ -12,6 +12,7 @@ import net.minecraftforge.fluids.*; import train.common.adminbook.ServerLogger; import train.common.entity.rollingStock.EntityTankLava; +import train.common.library.ItemIDs; import javax.annotation.Nullable; @@ -22,20 +23,18 @@ public class LiquidTank extends EntityRollingStock implements IFluidHandler, ISi private FluidTank theTank; public TileEntity[] blocksToCheck; - /** - * - * @param world - * @param fluid - * @param quantity - * @param capacity - */ - public LiquidTank(World world, Fluid fluid, int quantity) { - this(new FluidStack(fluid, quantity), world); - } - - public LiquidTank(World world) { - this(null, world); - } + /** + * + * @param world + * @param fluid + * @param quantity + */ + public LiquidTank(World world, Fluid fluid, int quantity) { + this(new FluidStack(fluid, quantity), world); + } + public LiquidTank(World world) { + this(null, world); + } private LiquidTank(@Nullable FluidStack liquid, World world) { super(world); @@ -141,29 +140,29 @@ public ItemStack checkInvent(ItemStack itemstack) { this.update += 1; if (this.update % 8 == 0 && itemstack != null) { ItemStack emptyItem = itemstack.getItem().getContainerItem(itemstack); - if (cargoItems[1] == null) { - if (theTank.getFluidAmount() == 0) { + if (cargoItems[1] == null) {// If the output slot is empty... + if (theTank.getFluidAmount() == 0) {// Adding the first fluid to the tank... for (Fluid fluid : FluidRegistry.getRegisteredFluids().values()) { if (LiquidManager.getInstance().containsFluid(itemstack, FluidRegistry.getFluidStack(FluidRegistry.getFluidName(fluid), 0))) { if (fluid.getTemperature() < 1000) { - if (!(this instanceof EntityTankLava)) { + if (!(this instanceof EntityTankLava)) {// Input fluid from itemstack (not lava or molten liquids). result = LiquidManager.getInstance().processContainer(this, 0, this, itemstack); break; } } else { - if (this instanceof EntityTankLava) { + if (this instanceof EntityTankLava) {// Input fluid from itemstack (lava or molten liquids). result = LiquidManager.getInstance().processContainer(this, 0, this, itemstack); break; } } } } - } else { + } else {// Output fluid into itemstack... result = LiquidManager.getInstance().processContainer(this, 0, this, itemstack); } - } else if (emptyItem != null) { - if (emptyItem.getItem() == cargoItems[1].getItem()) { + } else if (emptyItem != null) {// Adding or removing fluid to or from the tank (if the tank already has something in it). + if (emptyItem.getItem() == cargoItems[1].getItem()|| emptyItem.getItem().equals(ItemIDs.emptyCanister.item) && cargoItems[1].getItem().equals(ItemIDs.diesel.item)) { if (cargoItems[1].stackSize + 1 <= cargoItems[1].getMaxStackSize()) { result = LiquidManager.getInstance().processContainer(this, 0, this, itemstack); } diff --git a/src/main/java/train/common/core/CommonProxy.java b/src/main/java/train/common/core/CommonProxy.java index 1333002154..4be7a1986f 100644 --- a/src/main/java/train/common/core/CommonProxy.java +++ b/src/main/java/train/common/core/CommonProxy.java @@ -43,11 +43,13 @@ public class CommonProxy implements IGuiHandler { public static List playerList = new ArrayList(); public static boolean debug = false; - public void throwAlphaException() { + public static String configDirectory = "";public void throwAlphaException() { throw new IllegalStateException("You're trying to use a Traincraft alpha-version past its expiry date. Download a release-build at https://minecraft.curseforge.com/projects/traincraft."); } - public void setKeyBinding(String name, int value) { + public boolean isClient(){ + return true; + }public void setKeyBinding(String name, int value) { } public void registerRenderInformation() { diff --git a/src/main/resources/assets/tc/textures/gui/book/searchbar.png b/src/main/resources/assets/tc/textures/gui/book/searchbar.png new file mode 100644 index 0000000000..886145a552 Binary files /dev/null and b/src/main/resources/assets/tc/textures/gui/book/searchbar.png differ