/** Runes of Wizardry Mod for Minecraft * Licensed under the GNU GPL version 3 * * this file was created by Xilef11 on 2015-08-25 */ package com.zpig333.runesofwizardry.client.render; import java.awt.Color; import java.util.Set; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.GlStateManager; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.VertexBuffer; import net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer; import net.minecraft.client.renderer.vertex.DefaultVertexFormats; import net.minecraft.util.EnumFacing; import net.minecraft.util.ResourceLocation; import org.lwjgl.opengl.GL11; import com.zpig333.runesofwizardry.core.References; import com.zpig333.runesofwizardry.tileentity.TileEntityDustPlaced; /** Renders the placed dust * @author Xilef11 */ public class RenderDustPlaced extends TileEntitySpecialRenderer<TileEntityDustPlaced> { private static final ResourceLocation dustTexture = new ResourceLocation(References.texture_path + "textures/blocks/dust_top.png"); /* (non-Javadoc) * @see net.minecraft.client.renderer.tileentity.TileEntitySpecialRenderer#renderTileEntityAt(net.minecraft.tileentity.TileEntity, double, double, double, float, int) * see http://github.com/TheGreyGhost/MinecraftByExample/ MBE21 TESR */ @Override public void renderTileEntityAt(final TileEntityDustPlaced tileEntity, double relativeX, double relativeY, double relativeZ, float partialTicks, int blockDamageProgress) { try{ //save GL state GL11.glPushMatrix(); GL11.glPushAttrib(GL11.GL_ENABLE_BIT); //move the reference point from the player to the position of the block GlStateManager.translate(relativeX, relativeY, relativeZ); //grab the tesselator final Tessellator tesselator = Tessellator.getInstance(); final VertexBuffer buffer = tesselator.getBuffer(); //set texture this.bindTexture(dustTexture); //setup flags GL11.glDisable(GL11.GL_LIGHTING);//we want lighting (?) GL11.glEnable(GL11.GL_BLEND);//we want transparency blending(?) GL11.glDisable(GL11.GL_CULL_FACE);//visible from both faces (might solve being invisible) GL11.glDepthMask(false);//hidden behind other objects //drawing logic wrapped in a runnable Runnable draw = new Runnable(){ @Override public void run() { //drawing logic here //the central spots int[][] colors = tileEntity.getCenterColors(); for(int i=0;i<colors.length;i++){ for(int j=0;j<colors[i].length;j++){ if(colors[i][j]>=0){//negative colors indicate no rendering drawCenterVertex(i, j, colors[i][j], buffer, tesselator); } } } ///the internal connectors Set<int[]> connectors = tileEntity.getInternalConnectors(); for(int[] i : connectors){ drawInternalConnector(i[0], i[1], i[2], i[3], i[4], i[5], buffer, tesselator); } //external connectors for(int[]i:tileEntity.getExternalConnectors()){ drawExternalConnector(i[0], i[1], i[2], EnumFacing.getFront(i[3]), buffer, tesselator); } } }; draw.run(); //draw FX if its an active rune if(tileEntity.isInRune()&&tileEntity.getRune().renderActive){ //Note: lowering the scale "slows down" the animation runRendererWithGlint(draw, 1.5F); } }finally{//restore GL stuff GL11.glPopAttrib(); GL11.glPopMatrix(); } } private static final double offset = 0.058; final double y = 0.01;//y coordinate at which to draw the things private void drawCenterVertex(int row, int col, int colorInt, VertexBuffer renderer, Tessellator tes){ Color color = new Color(colorInt); double rowBegin = row/(float)TileEntityDustPlaced.ROWS + offset; double rowEnd = (row+1)/(float)TileEntityDustPlaced.ROWS - offset; double colBegin = col/(float)TileEntityDustPlaced.COLS + offset; double colEnd = (col+1)/(float)TileEntityDustPlaced.COLS - offset; final double[][] vertexTable = { {colBegin,y,rowBegin}, //numbers are X Y Z {colBegin,y,rowEnd}, {colEnd,y,rowEnd}, {colEnd,y,rowBegin} }; renderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); for(double[] vertex:vertexTable){ renderer.pos(vertex[0], vertex[1], vertex[2]).tex(vertex[0], vertex[2]).color(color.getRed(), color.getGreen(), color.getBlue(), 255).endVertex(); } tes.draw(); } private final static double thin = 0.02; private void drawInternalConnector(int row1, int col1, int row2, int col2, int color1, int color2, VertexBuffer buffer, Tessellator tes){ double row1begin = row1/(float)TileEntityDustPlaced.ROWS + offset, row1end = (row1+1)/(float)TileEntityDustPlaced.ROWS - offset, row2begin = row2/(float)TileEntityDustPlaced.ROWS + offset, //row2end = (row2+1)/(float)TileEntityDustPlaced.ROWS - offset, col1begin = col1/(float)TileEntityDustPlaced.COLS + offset, col1end = (col1+1)/(float)TileEntityDustPlaced.COLS - offset, col2begin = col2/(float)TileEntityDustPlaced.COLS + offset; //col2end = (col2+1)/(float)TileEntityDustPlaced.COLS - offset; double[][]vertexTable1=null,vertexTable2=null; double middle; if(row1==row2){//horizontal connector middle = col1end + ((col2begin - col1end)/2); vertexTable1 = new double[][]{ {col1end,y,row1begin+thin}, {middle,y,row1begin+thin}, {middle,y,row1end-thin}, {col1end,y,row1end-thin} }; vertexTable2 = new double[][]{ {middle,y,row1begin+thin}, {col2begin,y,row1begin+thin}, {col2begin,y,row1end-thin}, {middle,y,row1end-thin} }; }else if(col1==col2){ middle = row1end + ((row2begin - row1end)/2); vertexTable1 = new double[][]{ {col1end-thin,y,row1end}, {col1end-thin,y,middle}, {col1begin+thin,y,middle}, {col1begin+thin,y,row1end} }; vertexTable2 = new double[][]{ {col1end-thin,y,middle}, {col1end-thin,y,row2begin}, {col1begin+thin,y,row2begin}, {col1begin+thin,y,middle} }; }else{ throw new IllegalArgumentException("Invalid internal connector"); } //safety if(vertexTable1==null ||vertexTable2==null)return; Color color = new Color(color1); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); for(double vertex[]:vertexTable1){ buffer.pos(vertex[0], vertex[1], vertex[2]).tex(vertex[0], vertex[2]).color(color.getRed(), color.getGreen(), color.getBlue(), 255).endVertex(); } tes.draw(); color=new Color(color2); buffer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); for(double vertex[]:vertexTable2){ buffer.pos(vertex[0], vertex[1], vertex[2]).tex(vertex[0], vertex[2]).color(color.getRed(), color.getGreen(), color.getBlue(), 255).endVertex(); } tes.draw(); } private void drawExternalConnector(int row, int col, int colorIn, EnumFacing direction, VertexBuffer renderer, Tessellator tes){ double rowBegin = row/(float)TileEntityDustPlaced.ROWS + offset; double rowEnd = (row+1)/(float)TileEntityDustPlaced.ROWS - offset; double colBegin = col/(float)TileEntityDustPlaced.COLS + offset; double colEnd = (col+1)/(float)TileEntityDustPlaced.COLS - offset; double[][] vertexTable = null; if(direction == EnumFacing.NORTH && row==0){//top row vertexTable = new double[][]{ {colBegin+thin,y,rowBegin}, {colBegin+thin,y,0}, {colEnd-thin,y,0}, {colEnd-thin,y,rowBegin} }; } if(direction==EnumFacing.SOUTH && row==TileEntityDustPlaced.ROWS-1){//bottom row vertexTable = new double[][]{ {colBegin+thin,y,rowEnd}, {colBegin+thin,y,1}, {colEnd-thin,y,1}, {colEnd-thin,y,rowEnd} }; } if(direction==EnumFacing.WEST && col==0){//left (west) column vertexTable = new double[][]{ {colBegin,y,rowBegin+thin}, {0,y,rowBegin+thin}, {0,y,rowEnd-thin}, {colBegin,y,rowEnd-thin} }; } if(direction==EnumFacing.EAST && col==TileEntityDustPlaced.COLS-1){//right (EAST) column vertexTable = new double[][]{ {colEnd,y,rowBegin+thin}, {1,y,rowBegin+thin}, {1,y,rowEnd-thin}, {colEnd,y,rowEnd-thin} }; } if(vertexTable==null)return;//should not happen Color colour = new Color(colorIn); renderer.begin(GL11.GL_QUADS, DefaultVertexFormats.POSITION_TEX_COLOR); for(double vertex[]:vertexTable){ renderer.pos(vertex[0], vertex[1], vertex[2]).tex(vertex[0], vertex[2]).color(colour.getRed(), colour.getGreen(), colour.getBlue(), 255).endVertex(); } tes.draw(); } public static final ResourceLocation RES_ITEM_GLINT = new ResourceLocation("textures/misc/enchanted_item_glint.png"); /** * Runs the given renderer wrapped in a Runnable as a renderer for the * enchantment glint effect. This only works if the current texture is not * changed during execution of the runnable. Also, the colour should not * be changed during rendering, or it will lead to some weird results. * Basically, the only things that should be done are Matrix transformations * and rendering calls of vertices. * <p> * If some of the settings are changed during the rendering call or if the * texture scale is wrong, this can lead to pretty weird results. If you use * this method you need to play around with the scale until you find a good * value. * <p> * Usage: * * <pre> * anyRenderer(x, y, z); * runRendererWithGlint(new Runnable() { * public void run() { * anyRenderer(x, y, z); * } * }); * </pre> * <p> * <strong> * <em>The VertexBuffer needs to be off when this method is called!</em> * </strong><br> * <em>This discards the current texture</em> * * @param renderer * the renderer to run as a glint renderer. * @param textureScale * the scale of the texture. This sets the scale of the enchantment glint * texture parts. Some renderers need a value here in order to * display properly. You need to experiment a bit in order to find a good * value. For vanilla models, the standard value is 8. */ //http://www.minecraftforge.net/forum/index.php/topic,29902.0.html public void runRendererWithGlint(Runnable renderer, float textureScale) { GlStateManager.depthMask(false); //GlStateManager.depthFunc(GL11.GL_EQUAL); GlStateManager.disableLighting(); GlStateManager.blendFunc(GL11.GL_SRC_COLOR, GL11.GL_ONE); GlStateManager.alphaFunc(GL11.GL_GREATER, 0.1f); //enableBlend(true); GL11.glEnable(GL11.GL_BLEND); //bindTexture(new ResourceLocation("textures/misc/enchanted_item_glint.png")); this.bindTexture(RES_ITEM_GLINT); GL11.glPushMatrix(); // Push MODEL GlStateManager.matrixMode(GL11.GL_TEXTURE); GL11.glPushMatrix(); // Push TEXTURE GL11.glScalef(textureScale, textureScale, textureScale); float f = Minecraft.getSystemTime() % 3000L / 3000.0F / textureScale; GL11.glTranslatef(f, 0.0F, 0.0F); GL11.glRotatef(-50.0F, 0.0F, 0.0F, 1.0F); GlStateManager.matrixMode(GL11.GL_MODELVIEW); //setColor(new Color(0.5, 0.2, 0.8)); GL11.glColor3d(0.5, 0.2, 0.8); renderer.run(); GL11.glPopMatrix(); // Pop MODEL GL11.glPushMatrix(); // Push MODEL GlStateManager.matrixMode(GL11.GL_TEXTURE); GL11.glPopMatrix(); // Pop TEXTURE GL11.glPushMatrix(); // Push TEXTURE GL11.glScalef(textureScale, textureScale, textureScale); float f1 = Minecraft.getSystemTime() % 4873L / 4873.0F / textureScale; GL11.glTranslatef(-f1, 0.0F, 0.0F); GL11.glRotatef(10.0F, 0.0F, 0.0F, 1.0F); GlStateManager.matrixMode(GL11.GL_MODELVIEW); //setColor(new Color(0.5, 0.2, 0.8)); GL11.glColor3d(0.5, 0.2, 0.8); renderer.run(); GL11.glPopMatrix(); // Pop MODEL GlStateManager.matrixMode(GL11.GL_TEXTURE); GL11.glPopMatrix(); // Pop TEXTURE GlStateManager.matrixMode(GL11.GL_MODELVIEW); GlStateManager.blendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); GlStateManager.enableLighting(); GlStateManager.depthFunc(GL11.GL_LEQUAL); GlStateManager.depthMask(true); } }