@SideOnly(Side.CLIENT)
public class CanvasRenderer implements IItemRenderer{
	public static boolean overrideUseRenderHelper = false;
	
    @Override
    public boolean handleRenderType(ItemStack item, ItemRenderType type) {
        return type == ItemRenderType.INVENTORY ||
        		type == ItemRenderType.EQUIPPED ||
        		type == ItemRenderType.EQUIPPED_FIRST_PERSON ||
        		type == ItemRenderType.ENTITY;
    }

    @Override
    public boolean shouldUseRenderHelper(ItemRenderType type, ItemStack item, ItemRendererHelper helper) {
    	if(overrideUseRenderHelper)return true;
    	if(type == ItemRenderType.ENTITY){
    		return helper == ItemRendererHelper.ENTITY_ROTATION ||
    			   helper == ItemRendererHelper.ENTITY_BOBBING;
    	}
        return false;
    }

    @Override
    public void renderItem(ItemRenderType type, ItemStack item, Object... data) {
        
    	IIcon icon = ModMinePainter.canvas.item.getIconFromDamage(0);
    	if(item.hasTagCompound()){
    		PaintingIcon pi = PaintingCache.get(item);
    		GL11.glBindTexture(GL11.GL_TEXTURE_2D, pi.glTexId());
    		icon = pi;
    	}
        if(type == ItemRenderType.INVENTORY)
        	renderInventory(icon);
        else if(type == ItemRenderType.EQUIPPED || type == ItemRenderType.EQUIPPED_FIRST_PERSON)
        	renderEquipped(icon);
        else{
        	GL11.glTranslatef(-0.5f, 0, 0);
        	renderEquipped(icon);
        }
    }
    
    private void renderInventory(IIcon icon)
    {
        Tessellator tes = Tessellator.instance;
        tes.startDrawingQuads();
        tes.addVertexWithUV(1,  1,  0, icon.getMinU(), icon.getMinV());
        tes.addVertexWithUV(1,  15, 0, icon.getMinU(), icon.getMaxV());
        tes.addVertexWithUV(15, 15, 0, icon.getMaxU(), icon.getMaxV());
        tes.addVertexWithUV(15, 1,  0, icon.getMaxU(), icon.getMinV());
        tes.draw();
    }
    
    private void renderEquipped(IIcon icon)
    {
        Tessellator var5 = Tessellator.instance;
        float var7 = icon.getMinU();
        float var8 = icon.getMaxU();
        float var9 = icon.getMinV();
        float var10 = icon.getMaxV();
        ItemRenderer.renderItemIn2D(var5, var8, var9, var7, var10, 256, 256, 0.0625F);
    }
} public class ChiselItem extends Item{
	
	public ChiselItem(){
		super();
		this.setCreativeTab(ModMinePainter.tabMinePainter);
		this.setUnlocalizedName("chisel");
		this.setTextureName("minepainter:chisel");
		this.setMaxStackSize(1);
		this.setMaxDamage(960);
		this.setContainerItem(this);
		this.setFull3D();
	}
	
	@Override
    public boolean onItemUse(ItemStack is, EntityPlayer ep, World w, int x, int y, int z, int face, float xs, float ys, float zs) {
		if(!w.isRemote)return false;
		int[] pos = Operations.raytrace(x,y,z,ep); 
		
		int flags = this.getChiselFlags(ep);
		Block editBlock = this.getEditBlock(is);
		int editMeta = this.getEditMeta(is);
		if(!Operations.validOperation(w, x, y, z, pos, flags))
			return false;
		
		if(MinecraftServer.getServer() == null){
			boolean done = Operations.applyOperation(w, x, y, z, pos, flags,editBlock, editMeta);
			if(!done)return false;
		}
		
		ModMinePainter.network.sendToServer(new SculptureOperationMessage(pos,x,y,z,editBlock,editMeta,flags));
		
		w.playSoundEffect(x+0.5d, y+0.5d, z+0.5d, getEditBlock(is).stepSound.func_150496_b(), 0.5f, 0.5f);
		
		return true;
	}
	
	public Block getEditBlock(ItemStack is){
		return Blocks.air;
	}
	
	public int getEditMeta(ItemStack is){
		return 0;
	}
	
	public int getChiselFlags(EntityPlayer ep){
		return Operations.DAMAGE;
	}
	
	public static class Saw extends ChiselItem{

		public Saw(){
			super();
			this.setUnlocalizedName("saw");
			this.setTextureName("minepainter:saw");
		}

		@Override
		public int getChiselFlags(EntityPlayer ep){
			int axis = Operations.getLookingAxis(ep);
			switch(axis){
			case 0: return Operations.ALLY | Operations.ALLZ | Operations.DAMAGE;
			case 1: return Operations.ALLX | Operations.ALLZ | Operations.DAMAGE;
			case 2: return Operations.ALLX | Operations.ALLY | Operations.DAMAGE;
			}
			return 0;
		}
	}

	public static class Barcutter extends ChiselItem{
		
		public Barcutter(){
			super();
			this.setUnlocalizedName("barcutter");
			this.setTextureName("minepainter:shaver");
		}

		@Override
		public int getChiselFlags(EntityPlayer ep){
			int axis = Operations.getLookingAxis(ep);
			switch(axis){
			case 0: return Operations.ALLX | Operations.DAMAGE;
			case 1: return Operations.ALLY | Operations.DAMAGE;
			case 2: return Operations.ALLZ | Operations.DAMAGE;
			}
			return 0;
		}
	}

} public class PieceItem extends ChiselItem{

	public PieceItem(){
		this.setCreativeTab(null);
		this.setUnlocalizedName("sculpture_piece");
		this.setTextureName("");
		this.setHasSubtypes(true);
		this.setMaxStackSize(64);
		this.setMaxDamage(0);
		this.setContainerItem(null);
	}
	
	@Override public void registerIcons(IIconRegister r){}
	
	@Override
	public Block getEditBlock(ItemStack is){
		return Block.getBlockById( (is.getItemDamage() >> 4) & 0xfff);
	}
	
	@Override
	public int getEditMeta(ItemStack is){
		return is.getItemDamage() & 0xf;
	}
	
	@Override
	public int getChiselFlags(EntityPlayer ep){
		return Operations.PLACE | Operations.CONSUME;
	}
	
	public int getWorthPiece(){
		return 1;
	}
	
	public static class Bar extends PieceItem{
		@Override
		public int getChiselFlags(EntityPlayer ep){
			int axis = Operations.getLookingAxis(ep);
			switch(axis){
			case 0 : return Operations.PLACE | Operations.ALLX | Operations.CONSUME;
			case 1 : return Operations.PLACE | Operations.ALLY | Operations.CONSUME;
			case 2 : return Operations.PLACE | Operations.ALLZ | Operations.CONSUME;
			}
			return Operations.PLACE;
		}
		
		public int getWorthPiece(){
			return 8;
		}
	}
	
	public static class Cover extends PieceItem{
		@Override
		public int getChiselFlags(EntityPlayer ep){
			int axis = Operations.getLookingAxis(ep);
			switch(axis){
			case 0 : return Operations.PLACE | Operations.ALLY | Operations.ALLZ | Operations.CONSUME;
			case 1 : return Operations.PLACE | Operations.ALLX | Operations.ALLZ | Operations.CONSUME;
			case 2 : return Operations.PLACE | Operations.ALLX | Operations.ALLY | Operations.CONSUME;
			}
			return Operations.PLACE;
		}
		
		public int getWorthPiece(){
			return 64;
		}
	}
} public class PaintTool extends Item{
	
	public PaintTool(){
		this.setCreativeTab(ModMinePainter.tabMinePainter);
		this.setMaxStackSize(1);
	}

	public boolean onItemUse(ItemStack is, EntityPlayer ep, World w, int x, int y, int z, int face, float xs, float ys, float zs) {
		
		if(!w.isRemote)return false;
		
		boolean changed = paintAt(w,x,y,z,xs,ys,zs,getColor(ep,is), ep.isSneaking());
		
		if(changed)ModMinePainter.network.sendToServer(new PaintingOperationMessage(this,x,y,z,xs,ys,zs,getColor(ep,is)));
		
		return changed;
	}
	
	public int getColor(EntityPlayer ep, ItemStack is){
		int size = ep.inventory.getSizeInventory();
		for(int i = 0; i < size; i ++){
			ItemStack slot = ep.inventory.getStackInSlot(i);
			if(slot == null)continue;
			if(!(slot.getItem() instanceof Palette))continue;
			
			return Palette.getColors(slot)[0];
		}
		return 0;
	}
	
	public boolean apply(BufferedImage img, float[] point, int color, boolean isSneaking) {
		return false;
	}
	
	public boolean inBounds(int x,int y){
		return x>=0 && x<16 && y>=0 && y<16;
	}
	
	public boolean paintAt(World w,int x,int y,int z,float xs,float ys,float zs,int color,boolean isSneaking){
		if(w.getBlock(x, y, z) != ModMinePainter.painting.block)return false;
		PaintingEntity pe = Utils.getTE(w, x, y, z);
		if(pe == null)return false;
		PaintingPlacement place = PaintingPlacement.of(w.getBlockMetadata(x, y, z));
		float[] point = place.block2painting(xs, ys, zs);
		
		boolean changed = false;
		for(int i = -1;i<=1;i++)
			for(int j = -1;j<=1;j++){
				int _x = x + place.xpos.offsetX * i + place.ypos.offsetX * j;
				int _y = y + place.xpos.offsetY * i + place.ypos.offsetY * j;
				int _z = z + place.xpos.offsetZ * i + place.ypos.offsetZ * j;
				
				if(w.getBlock(_x, _y, _z) != ModMinePainter.painting.block)continue;
				if(w.getBlockMetadata(_x, _y, _z) != place.ordinal())continue;
				
				PaintingEntity painting = Utils.getTE(w, _x, _y, _z);
				
				point[0] -= i;
				point[1] -= j;
				boolean _changed = apply(painting.image, point, color, isSneaking);
				point[0] += i;
				point[1] += j;
				
				if(_changed){
					if(w.isRemote)pe.getIcon().fill(pe.image);
					else w.markBlockForUpdate(_x, _y, _z);
					changed = true;
				}
			}
		return changed;
	}

	public static class Mini extends PaintTool{
		
		public Mini(){
			super();
			this.setUnlocalizedName("mini_brush");
			this.setTextureName("minepainter:brush_small");
		}
		
		@Override public boolean apply(BufferedImage img, float[] point, int color, boolean isSneaking){
			
			int x = (int) (point[0] * 16 + 16) - 16;
			int y = (int) (point[1] * 16 + 16) - 16;
			
			if(!inBounds(x,y))return false;
			
			img.setRGB(x, y, color);
			return true;
		}
	}
	
	public static class Bucket extends PaintTool{
		IIcon fill;
		public Bucket(){
			super();
			this.setUnlocalizedName("paint_bucket");
			this.setTextureName("minepainter:bucket");
			this.setHasSubtypes(true);
		}
		
		@Override public ItemStack onItemRightClick(ItemStack is, World w, EntityPlayer ep){
			MovingObjectPosition mop = this.getMovingObjectPositionFromPlayer(w, ep, true);
			if(mop == null)return is;
			Material m = w.getBlock(mop.blockX, mop.blockY, mop.blockZ).getMaterial();
			if(m.isLiquid())return new ItemStack(Items.bucket);
			return is;
		}
		
		@Override public boolean requiresMultipleRenderPasses(){
	        return true;
	    }
		
	    @Override public int getRenderPasses(int metadata){
			return 2;
		}
	    
	    @Override public IIcon getIcon(ItemStack is, int renderPass){
			if(renderPass == 0)return itemIcon;
			return fill;
		}
	    
	    @SideOnly(Side.CLIENT) @Override public void registerIcons(IIconRegister par1IconRegister){
	        super.registerIcons(par1IconRegister);
	        fill = par1IconRegister.registerIcon("minepainter:bucket_fill");
	    }
	    
	    @Override public int getColorFromItemStack(ItemStack par1ItemStack, int par2){
			if(par2==1)return getColor(par1ItemStack.getItemDamage(),0);
			return super.getColorFromItemStack(par1ItemStack, par2);
		}
	    
	    @Override public int getColor(EntityPlayer ep, ItemStack is){
	    	return getColor(is.getItemDamage(), 0xff000000);
	    }
	    
	    private int getColor(int dmg, int mask){
	    	if(dmg<16)return ItemDye.field_150922_c[dmg] | mask;
	    	return 0xffffff;
	    }
		
		@Override public boolean apply(BufferedImage img, float[] point, int color,boolean isSneaking){
			
			int x = (int) (point[0] * 16 + 16) - 16;
			int y = (int) (point[1] * 16 + 16) - 16;
			
			if(!inBounds(x,y))return false;
			
			int from_color = img.getRGB(x, y);
			
			for(int i = 0; i < 256; i ++){
				x = i / 16;
				y = i % 16;
				img.setRGB(x, y, color);
			}
			
			return true;
		}
	}
	
	public static class Mixer extends PaintTool{
		
		public Mixer(){
			super();
			this.setUnlocalizedName("mixer_brush").setTextureName("minepainter:brush");
		}
		
		@Override public boolean apply(BufferedImage img, float[] point, int color, boolean isSneaking){
			
			int x = (int) (point[0] * 16 + 16) - 16;
			int y = (int) (point[1] * 16 + 16) - 16;
			
			int a75 = (int)(((color >> 24) & 0xff) * 0.75f) << 24; 
			a75 += color & 0xffffff;
			int a50 = (int)(((color >> 24) & 0xff) * 0.5f) << 24;
			a50 += color & 0xffffff;
			
			boolean changed = false;
			for(int i = -1; i <=1; i++)
				for(int j = -1; j <= 1; j++){
					if(!inBounds(x+i,y+j))continue;
					changed = true;
					
					int to_blend = Math.abs(i) + Math.abs(j);
					if(to_blend == 0)to_blend = color;
					else if(to_blend == 1)to_blend = a75;
					else to_blend = a50;
					
					img.setRGB(x+i, y+j, mix(to_blend, img.getRGB(x+i, y+j)));
				}
			return changed;
		}
		
		private int mix(int color,int original){
			float a_alpha = (color >> 24 & 0xFF) / 255.0F;
		    float b_alpha = (original >> 24 & 0xFF) / 255.0F;
		    float c_alpha = a_alpha + b_alpha * (1.0F - a_alpha);
		    int result = 0;

		    for (int b = 0; b < 24; b += 8)
		    {
		      int ca = color >> b & 0xFF;
		      ca = (int)(ca * a_alpha);
		      int cb = original >> b & 0xFF;
		      cb = (int)(cb * b_alpha * (1.0F - a_alpha));
		      result += ((int)((ca + cb) / c_alpha) << b);
		    }

		    result += ((int)(255.0F * c_alpha) << 24);
		    return result;
		}
		
	}
	
	public static class Eraser extends Mixer{
		public Eraser(){
			super();
			this.setUnlocalizedName("eraser").setTextureName("minepainter:eraser");
		}
		
		@Override public boolean apply(BufferedImage img, float[] point, int color, boolean isSneaking){
			
			int x = (int) (point[0] * 16 + 16) - 16;
			int y = (int) (point[1] * 16 + 16) - 16;
			
			boolean changed = false;
			for(int i = -1; i <=1; i++)
				for(int j = -1; j <= 1; j++){
					if(isSneaking && (i != 0 || j != 0))continue;
					if(!inBounds(x+i,y+j))continue;
					changed = true;
					
					color = img.getRGB(x+i, y+j);
					int a75 = (int)(((color >> 24) & 0xff) * 0.75f) << 24; 
					a75 += color & 0xffffff;
					int a50 = (int)(((color >> 24) & 0xff) * 0.5f) << 24;
					a50 += color & 0xffffff;
					
					int to_blend = Math.abs(i) + Math.abs(j);
					if(to_blend == 0)to_blend = 0;
					else if(to_blend == 1)to_blend = a50;
					else to_blend = a75;
					
					img.setRGB(x+i, y+j, to_blend);
				}
			return changed;
		}
	}
} public class PaintingBlock extends BlockContainer{

	public boolean ignore_bounds_on_state;
	
	public PaintingBlock() {
		super(Material.cloth);
		this.setBlockTextureName("minepainter:palette");
		this.setHardness(0.2f);
		this.setBlockName("painting");
	}

    @Override public void registerBlockIcons(IIconRegister register){}

	@Override public TileEntity createNewTileEntity(World var1, int var2) {
		return new PaintingEntity();
	}
	
	@Override public boolean isOpaqueCube()
	{
		return false;
	}

    @Override public boolean renderAsNormalBlock()
	{
		return false;
	}

    @Override public AxisAlignedBB getCollisionBoundingBoxFromPool(World par1World, int par2, int par3, int par4) {
        return null;
    }
    
    @Override public void setBlockBoundsBasedOnState(IBlockAccess iba,int x,int y,int z) {
    	if(ignore_bounds_on_state)return;
    	PaintingPlacement placement = PaintingPlacement.of(iba.getBlockMetadata(x, y, z));
    	placement.setBlockBounds(this);
    }
    
    @Override public void setBlockBoundsForItemRender() {
    	this.setBlockBounds(0, 0, 0, 1, 1, 1);
    }
    
    @Override public int getRenderType(){
    	return -1;
    }
    
    @Override public ItemStack getPickBlock(MovingObjectPosition target, World world,int x,int y,int z){
    	ItemStack is = new ItemStack(ModMinePainter.canvas.item);
    	NBTTagCompound nbt = new NBTTagCompound();
    	PaintingEntity pe = Utils.getTE(world, x, y, z);
    	
    	pe.writeImageToNBT(nbt);
    	is.setTagCompound(nbt);
    	return is;
    }
    
    @Override
    public void onNeighborBlockChange(World w, int x, int y, int z, Block block) {
    	PaintingPlacement pp = PaintingPlacement.of(w.getBlockMetadata(x, y, z));
    	int tx = x - pp.normal.offsetX;
    	int ty = y - pp.normal.offsetY;
    	int tz = z - pp.normal.offsetZ;
    	if(w.getBlock(tx, ty, tz).getMaterial().isSolid())return;
    	
    	w.setBlockToAir(x, y, z);
    }
    
    protected ItemStack createStackedBlock(int p_149644_1_){return null;}
    
    @Override @SideOnly(Side.CLIENT) public IIcon getIcon(int side, int meta){
		return Blocks.wool.getIcon(side, 0);
	}
    
    public Item getItemDropped(int p_149650_1_, Random p_149650_2_, int p_149650_3_)
    {
        return null;
    }
    
    @Override public void breakBlock(World w,int x,int y,int z,Block b, int meta){
    	
    	ItemStack is = new ItemStack(ModMinePainter.canvas.item);
    	NBTTagCompound nbt = new NBTTagCompound();
    	PaintingEntity pe = Utils.getTE(w, x, y, z);
    	
    	pe.writeImageToNBT(nbt);
    	is.setTagCompound(nbt);
    	this.dropBlockAsItem(w, x, y, z, is);
    	
    	super.breakBlock(w, x, y, z, b, meta);
    }
} public enum PaintingPlacement {

	UPXNEG(ForgeDirection.UP, ForgeDirection.WEST),
	UPXPOS(ForgeDirection.UP, ForgeDirection.EAST),
	UPZNEG(ForgeDirection.UP, ForgeDirection.NORTH),
	UPZPOS(ForgeDirection.UP, ForgeDirection.SOUTH),
	
	XNEG(ForgeDirection.WEST, ForgeDirection.DOWN),
	XPOS(ForgeDirection.EAST, ForgeDirection.DOWN),
	ZNEG(ForgeDirection.NORTH, ForgeDirection.DOWN),
	ZPOS(ForgeDirection.SOUTH, ForgeDirection.DOWN),
	
	DOWNXNEG(ForgeDirection.DOWN, ForgeDirection.WEST),
	DOWNXPOS(ForgeDirection.DOWN, ForgeDirection.EAST),
	DOWNZNEG(ForgeDirection.DOWN, ForgeDirection.NORTH),
	DOWNZPOS(ForgeDirection.DOWN, ForgeDirection.SOUTH);
	
	public static PaintingPlacement of(int id){
		return values()[id % values().length];
	}
	
	public static PaintingPlacement of(Vec3 vec, int face){
		
		ForgeDirection dir = ForgeDirection.getOrientation(face);
		switch(dir){
		case SOUTH: return ZPOS;
		case NORTH: return ZNEG;
		case WEST:  return XNEG;
		case EAST:  return XPOS;
		case DOWN:
			if(Math.abs(vec.xCoord) > Math.abs(vec.zCoord))
				return vec.xCoord > 0 ? DOWNXNEG : DOWNXPOS;
			return vec.zCoord > 0 ? DOWNZNEG: DOWNZPOS;
		case UP:
			if(Math.abs(vec.xCoord) > Math.abs(vec.zCoord))
				return vec.xCoord > 0 ? UPXNEG : UPXPOS;
			return vec.zCoord > 0 ? UPZNEG: UPZPOS;
		default:
			return null;
		}
	}
	
	ForgeDirection normal, ypos, xpos;

	PaintingPlacement(ForgeDirection normal, ForgeDirection ypos){
		this.normal = normal;
		this.ypos = ypos;
		this.xpos = normal.getRotation(ypos);
	}
	
	public float[] painting2blockWithShift(float x,float y,float shift){
		float[] point = new float[3];
		point[0] = (1-(xpos.offsetX + ypos.offsetX + normal.offsetX))/2;
		point[1] = (1-(xpos.offsetY + ypos.offsetY + normal.offsetY))/2;
		point[2] = (1-(xpos.offsetZ + ypos.offsetZ + normal.offsetZ))/2;
		point[0] += xpos.offsetX * x + ypos.offsetX * y + normal.offsetX*shift;
		point[1] += xpos.offsetY * x + ypos.offsetY * y + normal.offsetY*shift;
		point[2] += xpos.offsetZ * x + ypos.offsetZ * y + normal.offsetZ*shift;
		return point;
	}
	
	public float[] painting2block(float x,float y){
		return painting2blockWithShift(x,y,1/16f);
	}
	
	public float[] block2painting(float x,float y,float z){
		float [] point = new float[2];
		point[0] = (1 - xpos.offsetX - xpos.offsetY - xpos.offsetZ)/2;
		point[1] = (1 - ypos.offsetX - ypos.offsetY - ypos.offsetZ)/2;
		point[0] += xpos.offsetX * x + xpos.offsetY * y + xpos.offsetZ * z;
		point[1] += ypos.offsetX * x + ypos.offsetY * y + ypos.offsetZ * z;
		return point;
	}
	
	public void setBlockBounds(Block b){
		b.setBlockBounds(0 + (1-normal.offsetX)/2,
						 0 + (1-normal.offsetY)/2,
						 0 + (1-normal.offsetZ)/2,
						 1 - (1+normal.offsetX)/2,
						 1 - (1+normal.offsetY)/2,
						 1 - (1+normal.offsetZ)/2);
	}
} public class Operations {
	
	public static int editSubBlock(World w, int[] minmax, int x,int y,int z, Block block, byte meta){
		int tx,ty,tz;
		int s = 0;
		
		LinkedList<int[]> droplist = new LinkedList<int[]>();
		
		for(int _x = minmax[0] ; _x < minmax[3]; _x ++)
			for(int _y = minmax[1] ; _y < minmax[4]; _y ++)
				for(int _z = minmax[2] ; _z < minmax[5]; _z ++){
					
					tx = x; ty = y; tz = z;
					
					while(_x > 7){ _x -= 8; tx++; }
					while(_y > 7){ _y -= 8; ty++; }
					while(_z > 7){ _z -= 8; tz++; }
					while(_x < 0){ _x += 8; tx--; }
					while(_y < 0){ _y += 8; ty--; }
					while(_z < 0){ _z += 8; tz--; }
					
					Block tgt_block = w.getBlock(tx, ty, tz);
					int tgt_meta = w.getBlockMetadata(tx, ty, tz);
					
					if(tgt_block == Blocks.air && block != Blocks.air)
						w.setBlock(tx, ty, tz, ModMinePainter.sculpture.block);
					else if(sculptable(tgt_block,tgt_meta))
						convertToFullSculpture(w,tx,ty,tz);
					
					if(w.getBlock(tx, ty, tz) != ModMinePainter.sculpture.block)
						continue;
					
					SculptureEntity se = (SculptureEntity) w.getTileEntity(tx, ty, tz);
					Block former = se.sculpture.getBlockAt(_x, _y, _z, null);
					int metaFormer = se.sculpture.getMetaAt(_x, _y, _z, null);
					addDrop(droplist, former, metaFormer);
					se.sculpture.setBlockAt(_x, _y, _z, block, meta);
					if(se.sculpture.isEmpty())w.setBlock(tx, ty, tz, Blocks.air);
					if(w.isRemote)se.getRender().changed  = true;
					else w.markBlockForUpdate(tx, ty, tz);
					s++;
				}
		for(int[] drop : droplist){
			if(drop[0] == 0)continue;
			dropScrap(w,x,y,z, Block.getBlockById(drop[0]), (byte) drop[1], drop[2]);
		}
		
		return s;
	}
	
	private static void addDrop(List<int[]> drops, Block block, int meta){
		int id  = Block.getIdFromBlock(block);
		for(int[] drop : drops){
			if(drop[0] == id && drop[1] == meta){
				drop[2] ++;
				return;
			}
		}
		drops.add(new int[]{id,meta,1});
	}
	
	public static void dropScrap(World w, int x,int y,int z, Block block, byte meta, int amount){
//		Debug.log("dropping " + block.getUnlocalizedName() + " on " + (w.isRemote ? "client" : "server"));
		if(block == Blocks.air)return;
		
		int covers = amount / 64;
		amount %= 64;
		int bars = amount / 8;
		amount %= 8;

		if(covers > 0){
			ItemStack is = new ItemStack(ModMinePainter.cover.item);
			is.stackSize = covers;
			is.setItemDamage((Block.getIdFromBlock(block) << 4) + meta);
			ModMinePainter.sculpture.block.dropScrap(w, x, y, z, is);
		}
		
		if(bars > 0){
			ItemStack is = new ItemStack(ModMinePainter.bar.item);
			is.stackSize = bars;
			is.setItemDamage((Block.getIdFromBlock(block) << 4) + meta);
			ModMinePainter.sculpture.block.dropScrap(w, x, y, z, is);
		}
		
		if(amount > 0){
			ItemStack is = new ItemStack(ModMinePainter.piece.item);
			is.stackSize = amount;
			is.setItemDamage((Block.getIdFromBlock(block) << 4) + meta);
			ModMinePainter.sculpture.block.dropScrap(w, x, y, z, is);
		}
	}
	
	public static boolean sculptable(Block b, int blockMeta)
	{
		if(b == null)return false;
		
		if(b == Blocks.grass)return false;
		if(b == Blocks.bedrock)return false;
		if(b == Blocks.cactus)return false;
		if(b == Blocks.glass)return true;
		if(b == Blocks.stained_glass)return true;
		if(b == Blocks.leaves)return false;

		if(b.hasTileEntity(blockMeta))return false;
		if(!b.renderAsNormalBlock())return false;
		
		if(b.getBlockBoundsMaxX()!=1.0f)return false;
		if(b.getBlockBoundsMaxY()!=1.0f)return false;
		if(b.getBlockBoundsMaxZ()!=1.0f)return false;
		if(b.getBlockBoundsMinX()!=0.0f)return false;
		if(b.getBlockBoundsMinY()!=0.0f)return false;
		if(b.getBlockBoundsMinZ()!=0.0f)return false;
		
		
		return true;
	}
	
	public static void convertToFullSculpture(World w, int x,int y, int z){
		Block was = w.getBlock(x, y, z);
		int meta = w.getBlockMetadata(x, y, z);
		w.setBlock(x, y, z, ModMinePainter.sculpture.block);
		SculptureEntity se = (SculptureEntity) w.getTileEntity(x, y, z);
		for(int i = 0 ; i < 512; i ++){
			se.sculpture.setBlockAt((i>>6)&7, (i>>3)&7, (i>>0)&7, was, (byte)meta);
		}
	}
	
	static double length;
	static int[] xyzf = new int[]{-1,-1,-1,-1};
	
	public static int[] raytrace(int x,int y,int z, EntityPlayer ep){
		Block sculpture = ep.worldObj.getBlock(x,y,z);
		Sculpture the_sculpture = null;
		if(sculpture == ModMinePainter.sculpture.block){
			SculptureEntity se = Utils.getTE(ep.worldObj, x, y, z);
			the_sculpture = se.sculpture();
		}
		
		Vec3 from = ep.getPosition(1.0f);
		from = from.addVector(-x,-y,-z);
		Vec3 look = ep.getLookVec();
		
		return raytrace(the_sculpture, from,from.addVector(look.xCoord * 5, look.yCoord * 5, look.zCoord * 5));
	}
	
	public static int[] raytrace(Sculpture sculpture, Vec3 start, Vec3 end){
		xyzf[0] = xyzf[1] = xyzf[2] = xyzf[3] = -1; 
		length = Double.MAX_VALUE;
		
		for(int x = 0; x <= 8; x ++){

			Vec3 hit = start.getIntermediateWithXValue(end, x/8f);
			if(hit == null)continue;
			
			if(hit.yCoord < 0)continue;
			if(hit.zCoord < 0)continue;
			int y = (int)(hit.yCoord * 8);
			int z = (int)(hit.zCoord * 8);

			if(end.xCoord > start.xCoord)updateRaytraceResult(sculpture, x,y,z,ForgeDirection.WEST.ordinal(), 
					hit.subtract(start).lengthVector());
			else updateRaytraceResult(sculpture, x-1,y,z, ForgeDirection.EAST.ordinal(), 
					hit.subtract(start).lengthVector());
		}
		
		for(int y = 0; y <= 8; y ++){
			
			Vec3 hit = start.getIntermediateWithYValue(end, y/8f);
			if(hit == null)continue;
			
			if(hit.xCoord < 0)continue;
			if(hit.zCoord < 0)continue;
			int x = (int)(hit.xCoord * 8);
			int z = (int)(hit.zCoord * 8);
			
			if(end.yCoord > start.yCoord)updateRaytraceResult(sculpture,x,y,z, ForgeDirection.DOWN.ordinal(),
					hit.subtract(start).lengthVector());
			else updateRaytraceResult(sculpture,x,y-1,z,ForgeDirection.UP.ordinal(),
					hit.subtract(start).lengthVector());
		}
		
		for(int z = 0; z <= 8; z ++){
			
			Vec3 hit = start.getIntermediateWithZValue(end, z/8f);
			if(hit == null)continue;
			
			if(hit.xCoord < 0)continue;
			if(hit.yCoord < 0)continue;
			int x = (int)(hit.xCoord * 8);
			int y = (int)(hit.yCoord * 8);
			
			if(end.zCoord > start.zCoord)updateRaytraceResult(sculpture,x,y,z,ForgeDirection.NORTH.ordinal(),
					hit.subtract(start).lengthVector());
			else updateRaytraceResult(sculpture,x,y,z-1,ForgeDirection.SOUTH.ordinal(),
					hit.subtract(start).lengthVector());
		}
		
		return xyzf;
	}
	
	private static void updateRaytraceResult(Sculpture sculpture, int x,int y,int z,int f, double len){
		if(!Sculpture.contains(x,y,z))return;
		if(sculpture != null){
			if(sculpture.getBlockAt(x, y, z, null) == Blocks.air)return;
		}
		if(len >= length)return;
		
		length = len;
		xyzf[0] = x; xyzf[1] = y; xyzf[2] = z;  xyzf[3] = f;
	}
	
	public static final int PLACE = 1;
	public static final int ALLX = 2;
	public static final int ALLY = 4;
	public static final int ALLZ = 8;
	public static final int DAMAGE = 16;
	public static final int CONSUME = 32;
	public static final int TRANSMUTE = 64;
	
	public static void setBlockBoundsFromRaytrace(int[] pos, Block block, int type){
		pos = pos.clone();
		if(hasFlag(type, PLACE)){
			ForgeDirection dir = ForgeDirection.getOrientation(pos[3]);
			pos[0] += dir.offsetX;
			pos[1] += dir.offsetY;
			pos[2] += dir.offsetZ;
		}
		
		int x=0,y=0,z=0;
		
		while(pos[0] < 0){ pos[0] += 8;  x--;}
		while(pos[0] > 7){ pos[0] -= 8;  x++;}
		while(pos[1] < 0){ pos[1] += 8;  y--;}
		while(pos[1] > 7){ pos[1] -= 8;  y++;}
		while(pos[2] < 0){ pos[2] += 8;  z--;}
		while(pos[2] > 7){ pos[2] -= 8;  z++;}
		
		boolean allx = (type & ALLX) > 0;
		boolean ally = (type & ALLY) > 0;
		boolean allz = (type & ALLZ) > 0;
		block.setBlockBounds(allx ? x+0 : x+pos[0]/8f, 
				             ally ? y+0 : y+pos[1]/8f,
				             allz ? z+0 : z+pos[2]/8f,
		            		 allx ? x+1 : x+(pos[0]+1)/8f, 
				             ally ? y+1 : y+(pos[1]+1)/8f,
				             allz ? z+1 : z+(pos[2]+1)/8f);
	}

	public static boolean validOperation(World worldObj, int x, int y, int z,
			int[] pos, int chiselFlags) {
		
		pos= pos.clone();
		if(hasFlag(chiselFlags, PLACE)){
			ForgeDirection dir = ForgeDirection.getOrientation(pos[3]);
			pos[0] += dir.offsetX;
			pos[1] += dir.offsetY;
			pos[2] += dir.offsetZ;
		}
		
		while(pos[0] < 0){ pos[0] += 8; x--; }
		while(pos[0] > 7){ pos[0] -= 8; x++; }
		while(pos[1] < 0){ pos[1] += 8; y--; }
		while(pos[1] > 7){ pos[1] -= 8; y++; }
		while(pos[2] < 0){ pos[2] += 8; z--; }
		while(pos[2] > 7){ pos[2] -= 8; z++; }
		
		Block b = worldObj.getBlock(x, y, z);
		if(hasFlag(chiselFlags, PLACE)){
			if(b == Blocks.air)return true;
			if(b == ModMinePainter.sculpture.block)return true;
			return false;
		}else{
			int meta = worldObj.getBlockMetadata(x, y, z);
			if(b == Blocks.air){
				return false;
			}
			if(b == ModMinePainter.sculpture.block)return true;
			if(sculptable(b,meta))return true;
			return false;
		}
	}
	
	private static boolean hasFlag(int flags, int mask){
		return (flags & mask) > 0;
	}

	public static boolean applyOperation(World w, int x, int y, int z,
			int[] pos, int flags, Block editBlock, int editMeta) {

		if(hasFlag(flags, TRANSMUTE)){
			SculptureEntity se = Utils.getTE(w, x, y, z);
			int index = se.sculpture.getIndex(pos[0], pos[1], pos[2]);
			se.sculpture.block_ids[index] = Block.getIdFromBlock(editBlock);
			se.sculpture.block_metas[index] = (byte) editMeta;
			
			if(se.sculpture.isEmpty())w.setBlock(x,y,z, Blocks.air);
			if(w.isRemote)se.getRender().changed  = true;
			else w.markBlockForUpdate(x,y,z);
			
			return true;
		}
		
		pos= pos.clone();
		if(hasFlag(flags, PLACE)){
			ForgeDirection dir = ForgeDirection.getOrientation(pos[3]);
			pos[0] += dir.offsetX;
			pos[1] += dir.offsetY;
			pos[2] += dir.offsetZ;
		}
		
		while(pos[0] < 0){ pos[0] += 8; x--; }
		while(pos[0] > 7){ pos[0] -= 8; x++; }
		while(pos[1] < 0){ pos[1] += 8; y--; }
		while(pos[1] > 7){ pos[1] -= 8; y++; }
		while(pos[2] < 0){ pos[2] += 8; z--; }
		while(pos[2] > 7){ pos[2] -= 8; z++; }
		
		int[] minmax = new int[6];
		boolean allx = hasFlag(flags, ALLX);
		boolean ally = hasFlag(flags, ALLY);
		boolean allz = hasFlag(flags, ALLZ);
		minmax[0] = allx ? 0 : pos[0];
		minmax[1] = ally ? 0 : pos[1];
		minmax[2] = allz ? 0 : pos[2];
		minmax[3] = allx ? 8 : (pos[0]+1);
		minmax[4] = ally ? 8 : (pos[1]+1);
		minmax[5] = allz ? 8 : (pos[2]+1);
		
		int blocks = editSubBlock(w,minmax,x,y,z,editBlock,(byte) editMeta);
		
		return blocks > 0;
	}
	
	public static int getLookingAxis(EntityPlayer ep){
		Vec3 vec = ep.getLookVec();
		double x = Math.abs(vec.xCoord);
		double y = Math.abs(vec.yCoord);
		double z = Math.abs(vec.zCoord);
		if(x >= y && x >= z)return 0;
		if(y >= x && y >= z)return 1;
		if(z >= x && z >= y)return 2;
		return 0;
	}
} public class Sculpture {

	// layers of data.
	// combine bits at [x*8 + y] & (1<<z) for index
	// possible indexes : 2^#layers
	// start with 1 layer
	byte[][] layers;
	
	// block type index.
	// starts with 0 - air
	int[] block_ids;
	byte[] block_metas;
	int[] usage_count;
	
	Rotation r = new Rotation();
	
	public Sculpture(){
		normalize();
	}
	
	public Rotation getRotation(){
		return r;
	}
	
	public void write(NBTTagCompound nbt){
		nbt.setIntArray("block_ids", block_ids);
		nbt.setByteArray("block_metas", block_metas);
		for(int i = 0 ; i < layers.length; i ++)
			nbt.setByteArray("layer" + i, layers[i]);
		nbt.setByteArray("rotation", r.r);
	}
	
	public void read(NBTTagCompound nbt){
		block_ids = nbt.getIntArray("block_ids");
		block_metas = nbt.getByteArray("block_metas");
		r.r = nbt.getByteArray("rotation");
		layers = new byte[log(block_ids.length)][];
		for(int i = 0; i < layers.length; i ++)
			layers[i] = nbt.getByteArray("layer" + i);
		
		normalize();
	}
	
	public Block getBlockAt(int x,int y,int z, BlockSlice slice){
		if(!contains(x,y,z))
			return slice.getBlock(x, y, z);
		
		int index = getIndex(x,y,z);
		
		return Block.getBlockById(block_ids[index]);
	}
	
	public int getMetaAt(int x,int y,int z, BlockSlice slice){
		if(!contains(x,y,z))
			return slice.getBlockMetadata(x, y, z);
		
		int index = getIndex(x,y,z);
		
		return block_metas[index];
	}
	
	public boolean setBlockAt(int x,int y,int z,Block block, byte meta){
		if(!contains(x,y,z))return false;
		
		int index = findIndexForBlock(Block.getIdFromBlock(block), meta);
		if(index < 0){
			grow();
			index = block_ids.length/2;
			block_ids[index] = Block.getIdFromBlock(block);
			block_metas[index] = meta;
		}
		
		setIndex(x,y,z,index);		
		return true;
	}
	
	public boolean isEmpty(){
		int s = 0;
		for(int i = 0; i <block_ids.length;i++)
			if(block_ids[i]==0)s+=usage_count[i];
		return s == 512;
	}
	
	public boolean isFull(){
		int s = 0;
		for(int i = 0; i <block_ids.length;i++)
			if(block_ids[i]==0)s+=usage_count[i];
		return s == 0;
	}
	
	private int findIndexForBlock(int blockID, byte meta){
		for(int i = 0; i < block_ids.length; i++){
			if(block_ids[i] == blockID && block_metas[i] == meta){
				return i;
			}
		}
		for(int i = 0; i < block_ids.length; i++){
			if(usage_count[i] == 0){
				block_ids[i] = blockID;
				block_metas[i] = meta;
				return i;
			}
		}
		return -1;
	}
	
	int getIndex(int x, int y,int z){
		r.apply(x, y, z);
		int index = 0;
		for(int l = 0; l < layers.length; l ++)
			if( (layers[l][r.x*8 + r.y] & (1<<r.z)) > 0)index |= (1 << l);
		return index;
	}
	
	void setIndex(int x, int y,int z, int index){
		
		int prev = getIndex(x,y,z);
		usage_count[prev]--;
		usage_count[index]++;
		
		r.apply(x, y, z);
		for(int l = 0; l < layers.length; l ++)
			if( (index & (1 << l)) > 0)
				layers[l][r.x*8 + r.y] |= (1<<r.z);
			else layers[l][r.x*8 + r.y] &= ~(1<<r.z);
	}
	
	public static boolean contains(int x,int y,int z){
		return x>=0 && y>=0 && z>=0 && x<8 && y<8 && z<8; 
	}
	
	private boolean check(){
		if(block_ids == null)return false;
		if(block_metas == null)return false;
		if(layers == null)return false;
		if(r.r == null)return false;
		for(int i = 0; i <layers.length; i ++){
			if(layers[i] == null){
				Debug.log("layer " + i + " is null!" );
				return false;
			}
			if(layers[i].length != 64){
				Debug.log("layer " + i + " is " + layers[i].length + " long!");
				return false;
			}
		}
		if(block_ids.length != (1 << layers.length) )return false;
		if(block_ids.length != block_metas.length)return false;
		
		if(usage_count.length != block_ids.length)usage_count = new int[block_ids.length];
		return true;
	}
	
	private void grow(){
		byte[][] nlayers = new byte[layers.length + 1][];
		for(int i = 0; i < layers.length;i++)
			nlayers[i] = layers[i];
		nlayers[layers.length] = new byte[64];
		layers = nlayers;
		
		int[] ids = new int[block_ids.length * 2];
		for(int i = 0; i < block_ids.length;i++)ids[i]=block_ids[i];
		block_ids = ids;
		
		byte[] metas = new byte[block_metas.length * 2];
		for(int i = 0; i < block_metas.length;i++)metas[i]=block_metas[i];
		block_metas = metas;
		
		int[] usage = new int[usage_count.length * 2];
		for(int i = 0; i < usage_count.length;i++)usage[i]=usage_count[i];
		usage_count = usage;
	}
	
	private void normalize(){
		if(!check()){
			layers = new byte[1][64];
			block_ids = new int[2];
			block_metas = new byte[2];
			usage_count = new int[2];
		}
		for(int i = 0;i<usage_count.length;i++)usage_count[i] = 0;
		for(int i = 0; i < 512;i++){
			int index = getIndex(i >> 6, (i >> 3) & 7, i & 7);
			usage_count[index]++;
		}
	}
	
	private int log(int num){
		int i = 0;
		while(num > 1){
			num = num >> 1;
			i++;
		}
		return i;
	}

	// returns max light value
	public int getLight() {
		int light = 0;
		int current = 0;
		for(int i = 0; i < usage_count.length; i ++){
			if(usage_count[i] <= 0)continue;
			current = Block.getBlockById(block_ids[i]).getLightValue();
			if(current > light)light = current;
		}
		return light;
	}
	
	public int[][] getBlockSigs(){
		int[][] result = new int[2][usage_count.length];
		int s = 0;
		for(int i = 0; i < usage_count.length; i++){
			if(Block.getBlockById(block_ids[i]) == Blocks.air || usage_count[i] == 0)
				continue;
			result[0][s] = (block_ids[i] << 4) + block_metas[i];
			result[1][s] = usage_count[i];
			s++;
		}
		return result;
	}
	
	@SideOnly(Side.CLIENT)
	public boolean needRenderPass(int pass){
		for(int i = 0; i < usage_count.length; i++){
			Block that = Block.getBlockById(block_ids[i]); 
			if(that == Blocks.air || usage_count[i] == 0)
				continue;
			
			if(that.canRenderInPass(pass))return true;
		}
		return false;
	}
} public class SculptureEntity extends TileEntity{

	Sculpture sculpture = new Sculpture();
	Hinge hinge = null;
	final Nail nail = new Nail();
	
	@SideOnly(Side.CLIENT)
	private SculptureRenderCompiler render;
	
	public Sculpture sculpture(){
		return sculpture;
	}
	
	public Hinge getHinge(){
		return hinge;
	}
	
	public void setHinge(Hinge h){
		this.hinge = h;
	}
	
	public Nail getNail(){
		return nail;
	}
	
	@SideOnly(Side.CLIENT)
	public SculptureRenderCompiler getRender(){
		if(render == null)render = new SculptureRenderCompiler();
		return render;
	}
	
	@SideOnly(Side.CLIENT)
	public void updateRender(){
		if(this.worldObj.isRemote){
			BlockSlice slice = BlockSlice.at(worldObj, xCoord, yCoord, zCoord);
			getRender().update(slice);
			slice.clear();
		}
	}
	
    @Override @SideOnly(Side.CLIENT)
	public void invalidate()
	{
        super.invalidate();
        if(this.worldObj.isRemote)
        	getRender().clear();
	}
	
    @Override @SideOnly(Side.CLIENT)
	public void onChunkUnload()
	{
        super.onChunkUnload();
		if(this.worldObj.isRemote)
			getRender().clear();
	}

	//TileEntity util

	@Override
	public void writeToNBT(NBTTagCompound nbt)
	{
		super.writeToNBT(nbt);
		sculpture.write(nbt);
		if(hinge!=null)hinge.toNBT(nbt);
		nail.writeTo(nbt);
	}

	@Override
	public void readFromNBT(NBTTagCompound nbt)
	{
		if(worldObj != null && worldObj.isRemote)
			getRender().changed = true;
		super.readFromNBT(nbt);
		sculpture.read(nbt);
		hinge = Hinge.fromNBT(nbt);
		nail.readFrom(nbt);
	}
	
	public Packet getDescriptionPacket()
    {
        NBTTagCompound nbttagcompound = new NBTTagCompound();
        this.writeToNBT(nbttagcompound);
        return new S35PacketUpdateTileEntity(this.xCoord, this.yCoord, this.zCoord, 17, nbttagcompound);
    }

    public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity pkt)
    {
        readFromNBT(pkt.func_148857_g());
    }
} @SideOnly(Side.CLIENT)
public class SculptureRender implements ISimpleBlockRenderingHandler{
	
	@Override
	public void renderInventoryBlock(Block block, int metadata, int modelId,
			RenderBlocks renderer) {
	}

	@Override
	public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z,
			Block block, int modelId, RenderBlocks renderer) {

		if(world.getBlock(x, y, z) != ModMinePainter.sculpture.block)return false;
		
		SculptureEntity se = (SculptureEntity) world.getTileEntity(x, y, z);
		
		se.getRender().updateLight(block.getMixedBrightnessForBlock(world, x, y, z));
		se.getRender().updateAO(world, x, y, z);
		
		return false;
	}

	@Override
	public boolean shouldRender3DInInventory(int modelId) {
		return false;
	}

	@Override
	public int getRenderId() {
		return ModMinePainter.sculpture.renderID;
	}

} public class Debug {

	
	public static <T> void log(T... thing){
		StringBuilder sb = new StringBuilder();
		for(T i : thing)sb.append(i + ", ");
		System.err.println(sb.toString());
	}
	
} public class Utils {

	
	public static <T extends TileEntity> T getTE(IBlockAccess iba, int x,int y,int z){
		return (T) iba.getTileEntity(x, y, z);
	}
	
	public static <T extends Item> T getItem(ItemStack is){
		return (T) is.getItem();
	}
	
	public static void forEachInv(IInventory inv, IInvTraversal traversal){
		int size = inv.getSizeInventory();
		for(int i = 0; i < size; i ++){
			ItemStack is = inv.getStackInSlot(i);
			if(traversal.visit(i, is))return;
		}
	}
	
	public static interface IInvTraversal{
		public boolean visit(int i ,ItemStack is);
	}
}
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.EQUIPPED;
import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.BLOCK_3D;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import hx.minepainter.item.CanvasRenderer;
import hx.minepainter.item.ChiselItem;
import hx.minepainter.item.PieceItem;
import hx.minepainter.painting.PaintTool;
import hx.minepainter.painting.PaintingBlock;
import hx.minepainter.painting.PaintingPlacement;
import hx.minepainter.sculpture.Operations;
import hx.minepainter.sculpture.Sculpture;
import hx.minepainter.sculpture.SculptureEntity;
import hx.minepainter.sculpture.SculptureRender;
import hx.utils.Debug;
import hx.utils.Utils;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.entity.RenderManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraft.world.World;
import net.minecraftforge.client.IItemRenderer;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.event.DrawBlockHighlightEvent;
import net.minecraftforge.client.event.RenderPlayerEvent;
import net.minecraftforge.client.event.RenderWorldEvent;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.entity.EntityEvent;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
package hx.minepainter;




public class EventHandler {	
	
	@SideOnly(Side.CLIENT)
	@SubscribeEvent
	public void onDrawPlayerHelmet(RenderPlayerEvent.Specials.Pre event){
		if(!event.renderHelmet)return;
		
		ItemStack is = event.entityPlayer.getEquipmentInSlot(4);
		if(!needsHelmetRenderHook(is))return;
		
		event.renderHelmet = false;
		
		GL11.glPushMatrix();
		if(needsHeadHiding(is)){
			event.renderer.modelBipedMain.bipedHead.showModel = true;
			event.renderer.modelBipedMain.bipedHead.postRender(0.0625F);
			event.renderer.modelBipedMain.bipedHead.showModel = false;
		}else{
			event.renderer.modelBipedMain.bipedHead.postRender(0.0625F);
			GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
		}
    
        float f1 = 0.625F;
        GL11.glTranslatef(0.0F, -0.25F, 0.0F);
        GL11.glRotatef(90.0F, 0.0F, 1.0F, 0.0F);
        GL11.glScalef(f1, -f1, -f1);

        CanvasRenderer.overrideUseRenderHelper = true;
        RenderManager.instance.itemRenderer.renderItem(event.entityPlayer, is, 0);
        CanvasRenderer.overrideUseRenderHelper = false;
        
        GL11.glPopMatrix();
	}
	
	@SideOnly(Side.CLIENT) @SubscribeEvent
	public void onDrawPlayerHead(RenderPlayerEvent.Pre event){
		ItemStack is = event.entityPlayer.getEquipmentInSlot(4);
		if(!needsHeadHiding(is))return;
		
		event.renderer.modelBipedMain.bipedHead.showModel = false;
		event.renderer.modelBipedMain.bipedHeadwear.showModel = false;
	}
	
	@SideOnly(Side.CLIENT) @SubscribeEvent
	public void onDrawPlayerHead(RenderPlayerEvent.Post event){
		ItemStack is = event.entityPlayer.getEquipmentInSlot(4);
		if(!needsHeadHiding(is))return;
		
		event.renderer.modelBipedMain.bipedHead.showModel = true;
		event.renderer.modelBipedMain.bipedHeadwear.showModel = true;
	}
	
	@SideOnly(Side.CLIENT)
	private boolean needsHelmetRenderHook(ItemStack is){
		if(is == null)return false;
		if(is.getItem() == ModMinePainter.droppedSculpture.item)return true;
		if(is.getItem() == ModMinePainter.canvas.item)return true;
		return false;
	}
	
	@SideOnly(Side.CLIENT)
	private boolean needsHeadHiding(ItemStack is){
		if(is == null)return false;
		if(is.getItem() == ModMinePainter.droppedSculpture.item)return true;
		return false;
	}
	
	@SideOnly(Side.CLIENT)
	@SubscribeEvent
	public void onDrawBlockhightlight(DrawBlockHighlightEvent event){
		ItemStack is = event.player.getCurrentEquippedItem();
		if(is == null || !(is.getItem() instanceof ChiselItem))return;