package dangerzone.threads;
import dangerzone.Chunk;
import dangerzone.DangerZone;
import dangerzone.Ores;
import dangerzone.StitchedTexture;
import dangerzone.VBOBuffer;
import dangerzone.World;
import dangerzone.WorldRenderer;
import dangerzone.WorldRendererUtils;
import dangerzone.blocks.Blocks;

/*
 * This code is copyright Richard H. Clark, TheyCallMeDanger, OreSpawn, 2015-2020.
 * You may use this code for reference for modding the DangerZone game program,
 * and are perfectly welcome to cut'n'paste portions for your mod as well.
 * DO NOT USE THIS CODE FOR ANY PURPOSE OTHER THAN MODDING FOR THE DANGERZONE GAME.
 * DO NOT REDISTRIBUTE THIS CODE. 
 * 
 * This copyright remains in effect until January 1st, 2021. 
 * At that time, this code becomes public domain.
 * 
 * WARNING: There are bugs. Big bugs. Little bugs. Every size in-between bugs.
 * This code is NOT suitable for use in anything other than this particular game. 
 * NO GUARANTEES of any sort are given, either express or implied, and Richard H. Clark, 
 * TheyCallMeDanger, OreSpawn are not responsible for any damages, direct, indirect, or otherwise. 
 * You should have made backups. It's your own fault for not making them.
 * 
 * NO ATTEMPT AT SECURITY IS MADE. This code is USE AT YOUR OWN RISK.
 * Regardless of what you may think, the reality is, that the moment you 
 * connected your computer to the Internet, Uncle Sam, among many others, hacked it.
 * DO NOT KEEP VALUABLE INFORMATION ON INTERNET-CONNECTED COMPUTERS.
 * Or your phone...
 * 
 */



/*
 * Just scan the blocks and build VBO buffers.
 * Let the WorldRenderer handle all the actual graphics.
 * 
 */

public class VBODataBuilderThread implements Runnable {

	public World world = null;
	public int blockrenderwidth = 16;
	private static StitchedTexture st_last = null;
	private static VBOBuffer v_last = null;
	public static float cbr, cbg, cbb;
	public static float sunpostop, sunposleft, sunposright;
	private StitchedTexture rot_st[] = new StitchedTexture[6];
	private float tcoords[][] = new float[6][8];
	private float brightness_red, brightness_green, brightness_blue;
	private volatile boolean take_a_break = false;
	
	public VBODataBuilderThread(World w){
		world = w;
	}
	
	public void run() {

		int torender = 0;
		int i,j;
		int ci,cj;
		double pi = 3.1415926545D;
		double rdd, rr, rhdir;
		float dist = 0;
		int should_check;
		float f5yaw = 0;
		int renderclosedelta = 16;
		long currtime, lasttime;
		boolean allhere = false;
		
		brightness_red = brightness_green = brightness_blue = 0;
		lasttime = currtime = System.currentTimeMillis();
		
		while(DangerZone.gameover == 0){
			
			if(DangerZone.player.rotation_pitch_head < 45 || DangerZone.player.rotation_pitch_head > 315){ //looking down or up?
				torender = DangerZone.renderdistance;
			}else{
				torender = DangerZone.renderdistance - 2;
			}
			if(torender < 3)torender = 3;
			
			if(DangerZone.f5_front){			
				f5yaw = 180f;
			}else{
				f5yaw = 0;
			}
			
			double px, py, pz, tod;
			int pd = DangerZone.player.dimension;
			px = DangerZone.player.posx;
			py = DangerZone.player.posy;
			pz = DangerZone.player.posz;
			
			tod = world.getTimeOfDay();
			if(tod > world.getLengthOfDay()/2)tod -= world.getLengthOfDay()/2;
			tod /= world.getLengthOfDay();
			sunpostop = (float) (0.80f + 0.2f * Math.sin(Math.toRadians(360f*tod)));
			sunposleft = (float) (0.80f + 0.2f * Math.sin(Math.toRadians((360f*tod)+90f)));
			sunposright = (float) (0.80f + 0.2f * Math.sin(Math.toRadians((360f*tod)-90f)));
			
			//constantly render far away chunks (more than 1 away)
			//check in between each for elapsed time, and if expired, re-render the close ones!

			for(i=-torender;i<=torender;i++){
				for(j=-torender;j<=torender;j++){ 
					if(Math.sqrt((i*i)+(j*j))<=torender){
						if(Math.abs(i)>1 || Math.abs(j)>1){
							dist = (float) Math.sqrt(i*i + j*j);
							rr = (float) Math.atan2((j*16), (i*16));					
							rhdir = Math.toRadians(((getRotationYawHead()+f5yaw)-90)%360f); 
							rdd = Math.abs(rr - rhdir)%(pi*2.0D);
							if(rdd > pi)rdd = rdd-(pi*2.0D);
							rdd = Math.abs(rdd); //Total differential, minus sign.
							if(DangerZone.player.rotation_pitch_head < 45 || DangerZone.player.rotation_pitch_head > 315){ //looking down or up?
								if(dist > 8 && rdd > pi/3*DangerZone.fieldOfView/45.0f){
									//skipped++;
									continue; //Don't render what we can't see!
								}
								if(dist > 4 && rdd > pi/2*DangerZone.fieldOfView/45.0f){
									//skipped++;
									continue; //Don't render what we can't see!
								}
								if(dist > 1 && rdd > pi*3/4*DangerZone.fieldOfView/45.0f){
									//skipped++;
									if(!DangerZone.f5_front && !DangerZone.f5_back)continue; //Don't render what we can't see!
								}
							}	

							should_check = 1;							
							if(world.rand.nextInt((int)(dist/2)+2) != 0)should_check = 0;
							

							take_a_break = false;
							allhere = true;
							
							//make sure that surrounding chunks exist in cache, otherwise graphics thrashes a bit with the sides of
							//the chunk having to be drawn and then UN-drawn
							
							if(!world.chunkcache.chunkExists(pd, ((i-1)*16)+(int)px, 0, (j*16)+(int)pz)){
								world.chunkcache.getDecoratedChunk(pd, ((i-1)*16)+(int)px, 0, (j*16)+(int)pz);
								allhere = false;
							}
							if(!world.chunkcache.chunkExists(pd, ((i+1)*16)+(int)px, 0, (j*16)+(int)pz)){
								world.chunkcache.getDecoratedChunk(pd, ((i+1)*16)+(int)px, 0, (j*16)+(int)pz);
								allhere = false;
							}
							if(!world.chunkcache.chunkExists(pd, (i*16)+(int)px, 0, ((j-1)*16)+(int)pz)){
								world.chunkcache.getDecoratedChunk(pd, (i*16)+(int)px, 0, ((j-1)*16)+(int)pz);
								allhere = false;
							}
							if(!world.chunkcache.chunkExists(pd, (i*16)+(int)px, 0, ((j+1)*16)+(int)pz)){
								world.chunkcache.getDecoratedChunk(pd, (i*16)+(int)px, 0, ((j+1)*16)+(int)pz);
								allhere = false;
							}
							
							if(allhere){							
								if(renderChunk(world, i, j, torender, should_check, 1, pd, px, py, pz)){
									//it was a sizing pass. Do it for real this time.
									renderChunk(world, i, j, torender, should_check, 2, pd, px, py, pz);	
								}
							}else{
								take_a_break = true;
							}

							if(take_a_break){
								try {
									Thread.sleep(2);
									if(DangerZone.wr.fps < 40)Thread.sleep(4);
									if(DangerZone.wr.fps < 20)Thread.sleep(8);
								} catch (InterruptedException e) {
									//e.printStackTrace();
								}
							}
						}
						
						//Give the CPU a break if its struggling with graphics!
						try {
							if(DangerZone.wr.fps < 40)Thread.sleep(4);
							if(DangerZone.wr.fps < 20)Thread.sleep(8);
						} catch (InterruptedException e) {
							//e.printStackTrace();
						}
						
					}
						
					//check the time. Do we need to re-render the close chunks yet?
					//we like to do them about every one or two frames...
					//we do this so that there is no delay in placing or breaking blocks!
					currtime = System.currentTimeMillis();
					if(currtime-lasttime > renderclosedelta){
						lasttime = currtime;
						for(ci=-1;ci<=1;ci++){
							for(cj=-1;cj<=1;cj++){ 

								rr = (float) Math.atan2((cj*16), (ci*16));					
								rhdir = Math.toRadians(((getRotationYawHead()+f5yaw)-90)%360f); 
								rdd = Math.abs(rr - rhdir)%(pi*2.0D);
								if(rdd > pi)rdd = rdd-(pi*2.0D);
								rdd = Math.abs(rdd); //Total differential, minus sign.

								should_check = 1;

								if(renderChunk(world, ci, cj, torender, should_check, 1, pd, px, py, pz)){
									//it was a sizing pass. Do it for real this time.
									renderChunk(world, ci, cj, torender, should_check, 2, pd, px, py, pz);	
								}
							}
						}
					}
				}
			}

			renderclosedelta = 32; //skip a couple frames...
			if(DangerZone.wr.fps < 40)renderclosedelta = 128; 	//skip more
			if(DangerZone.wr.fps < 20)renderclosedelta = 512;	//about twice a second
			
			//System.out.printf("renderclosedelta = %d\n", renderclosedelta);
		}
	}
	
	private float getRotationYawHead(){
		return DangerZone.player.rotation_yaw_head; //put this in another routine and make it volatile so java will consistently get the latest value! maybe...
	}
	
	
	private boolean renderChunk(World world, int xrel, int zrel, int torender, int shouldcheck, int renderlevel, int pd, double px, double py, double pz){
		int i, j, k, bid, meta;
		int sides;
		int x, z;
		short leveldata[] = null;
		short levelmetadata[] = null;
		short prevleveldata[] = null;
		short nextleveldata[] = null;
		short cfrontleveldata[] = null;
		int cfrontleveldatavalid = 0;
		short cbackleveldata[] = null;
		int cbackleveldatavalid = 0;
		short cleftleveldata[] = null;
		int cleftleveldatavalid = 0;
		short crightleveldata[] = null;
		int crightleveldatavalid = 0;
		int starty = 0;
		int chunkX, chunkZ;
		int xpos, zpos;
		float lightmap[] = null;
		boolean focused = false;
		boolean drew_something = false;
		boolean leveldatainvalid = true;
		VBOBuffer v = null;
		int itemp;
		float dist;
		boolean bidSolid = false;
		int drawwidth = 8;
		boolean defective = false;
		
		if(DangerZone.f5_front || DangerZone.f5_back){
			drawwidth = 16;
		}
		
		cbr = cbg = cbb = 0;

		xpos = (xrel*16)+(int)px;
		zpos = (zrel*16)+(int)pz;
		chunkX = (xpos)>>4;
		chunkZ = (zpos)>>4;
		x = chunkX*16;
		z = chunkZ*16;
		dist = (float) Math.sqrt((xrel*xrel)+(zrel*zrel)); //chunk distance

		//This call is special. If the chunk is not in cache, it will just be ignored, but a request is sent to fetch it.
		Chunk c = world.chunkcache.getDecoratedChunk(pd, xpos, 0, zpos);
		if(c == null){
			//System.out.printf("Chunk get fail\n");
			return false;
		}
		
		WorldRenderer.VBOlistlock.lock();
		//reset existing vbos for this chunk, because we are about to rebuild them
		//this prevents a WHOLE BOATLOAD of re-extending new VBOs all the time...
		for(itemp=0;itemp<=20;itemp++){
			if(c.VBOids[itemp] <= 0)break;
			v = WorldRenderer.VBOmap.get(c.VBOids[itemp]);
			if(v != null){
				if(v.vbostate == 2){
					//System.out.printf("newvbodata not null\n");
					WorldRenderer.VBOlistlock.unlock();
					return false; //nevermind!
				}
			}else{
				//System.out.printf("missing vbo\n");
				defective = true;
			}
		}
		for(itemp=0;itemp<=20;itemp++){
			if(c.VBOids[itemp] <= 0)break;
			v = WorldRenderer.VBOmap.get(c.VBOids[itemp]);
			if(v != null){
				v.reset();
			}else{
				//System.out.printf("missing vbo 2\n");
				defective = true;
			}
		}
		
		if(defective){
			DangerZone.wr.deleteVBOlist(c.VBOids);
			c.VBOids = new long[20];
		}
		
		WorldRenderer.VBOlistlock.unlock();

		//if this chunk has been drawn at least once, we may be able to skip it.
		if(!defective && dist > 2){
			if(c.VBOids[0] > 0){
				if(renderlevel < 2){
					if(world.rand.nextInt((int)(dist/2) + 1) != 0)return false;
				}else{
					shouldcheck = 1; //real data pass
				}
			}else{
				shouldcheck = 1; ///sizing pass
				//System.out.printf("Virgin chunk %d, %d\n", c.chunkX, c.chunkZ);
			}
		}
		if(defective)shouldcheck = 1;
		
		st_last = null;
		v_last = null;
		
		//System.out.printf("redraw chunk %d, %d, %d\n", xpos>>4, zpos>>4, shouldcheck);
							
		starty = DangerZone.mindrawlevel;

		for(j=starty;j<256;j++){			
			recalcBrightness(pd, j);
			setVBOBrightness(0);
			crightleveldatavalid = 0;
			cleftleveldatavalid = 0;
			cbackleveldatavalid = 0;
			cfrontleveldatavalid = 0;
			if(c.redraw == 0 && shouldcheck == 0 && c.drawn[j] == 0){
					leveldatainvalid = true;
					continue; //if not re-checking, and didn't draw anything at this level last time, ignore...
			}
						
			if(!leveldatainvalid){	
				if(j < 255){				
					if(j > 0){
						prevleveldata = leveldata;
						leveldata = nextleveldata;
						nextleveldata = c.blockdata[j+1];
					}else{
						prevleveldata = null;					
						leveldata = c.blockdata[j];
						nextleveldata = c.blockdata[j+1];
					}
				}else{
					prevleveldata = leveldata;
					leveldata = nextleveldata;
					nextleveldata = null;				
				}
			}else{
				prevleveldata = null;
				if(j>0)prevleveldata = c.blockdata[j-1];
				leveldata = c.blockdata[j];
				nextleveldata = null;
				if(j<255)nextleveldata = c.blockdata[j+1];
				leveldatainvalid = false;
			}			
			
			if(leveldata == null){
				c.drawn[j] = 0;
				continue; //no sense trying if no data!
			}
			
			
			levelmetadata = c.metadata[j];
			lightmap = null;
			if(c.lightmap != null){
				lightmap = c.lightmap[j];
			}

			drew_something = false;
			
			setVBOBrightness(0);
			
			for(i=0;i<16;i++){
				for(k=0;k<16;k++){
					bid = leveldata[i*16+k];

					if(bid > 0 && bid < Blocks.blocksMAX && Blocks.BlockArray[bid] != null){
						meta = 0;
						if(levelmetadata != null)meta = levelmetadata[i*16+k];
						
						sides = 0;						  	
						bidSolid = Blocks.isSolidForRender(bid);

						if( DangerZone.all_sides || x+i > (int)px-drawwidth){ //Don't draw left if to the left...
							if(i > 0){
								if(shouldRenderSide(bid, bidSolid, leveldata[(i-1)*16+k]))sides |= 1;
							}else{
								if(cleftleveldatavalid == 0){
									cleftleveldata = world.chunkcache.getDecoratedChunkLevelData( pd, x+i-1,j,z+k);
									cleftleveldatavalid = 1;
								}
								if(cleftleveldata != null){
									if(shouldRenderSide(bid, bidSolid, cleftleveldata[((i-1)&0x0f)*16+k]))sides |= 1;
								}else{
									sides |= 1;
								}
							}
						}
						

						if( DangerZone.all_sides || x+i < (int)px+drawwidth){ //Don't draw right if to the right...
							if(i < 15){
								if(shouldRenderSide(bid, bidSolid, leveldata[(i+1)*16+k]))sides |= 2;
							}else{
								if(crightleveldatavalid == 0){
									crightleveldata = world.chunkcache.getDecoratedChunkLevelData(pd, x+i+1,j,z+k);
									crightleveldatavalid = 1;
								}
								if(crightleveldata != null){
									if(shouldRenderSide(bid, bidSolid, crightleveldata[((i+1)&0x0f)*16+k]))sides |= 2;
								}else{
									sides |= 2;
								}
							}
						}
											

						if( DangerZone.all_sides || z+k > (int)pz-drawwidth){ //Don't draw back if in front
							if(k > 0){
								if(shouldRenderSide(bid, bidSolid, leveldata[i*16+(k-1)]))sides |= 4;
							}else{
								if(cbackleveldatavalid == 0){
									cbackleveldata = world.chunkcache.getDecoratedChunkLevelData(pd, x+i,j,z+k-1);
									cbackleveldatavalid = 1;
								}
								if(cbackleveldata != null){
									if(shouldRenderSide(bid, bidSolid, cbackleveldata[i*16+((k-1)&0x0f)]))sides |= 4;
								}else{
									sides |= 4;
								}
							}
						}
						

						if( DangerZone.all_sides || z+k < (int)pz+drawwidth){ //Dont draw front if in back!
							if(k < 15){
								if(shouldRenderSide(bid, bidSolid, leveldata[i*16+(k+1)]))sides |= 8;
							}else{
								if(cfrontleveldatavalid == 0){
									cfrontleveldata = world.chunkcache.getDecoratedChunkLevelData(pd, x+i,j,z+k+1);
									cfrontleveldatavalid = 1;
								}
								if(cfrontleveldata != null){
									if(shouldRenderSide(bid, bidSolid, cfrontleveldata[i*16+((k+1)&0x0f)]))sides |= 8;
								}else{
									sides |= 8;
								}
							}
						}



						if( DangerZone.all_sides || j > (int)py-drawwidth){ //If above, check the bottom...
							if(prevleveldata == null){
								sides |= 0x10;
							}else{
								if(shouldRenderSide(bid, bidSolid, prevleveldata[i*16+k]))sides |= 0x10;
							}
						}							
						if(j < 255){
							if( DangerZone.all_sides || j < (int)py+drawwidth+2){ //If below, check the top...
								if(nextleveldata == null){
									sides |= 0x20;
								}else{
									if(shouldRenderSide(bid, bidSolid, nextleveldata[i*16+k]))sides |= 0x20;
								}
							}
						}else{
							sides |= 0x20;
						}
						
						
						//Must draw everything near focus if there is damage!
						if(WorldRenderer.focus_damage != 0){
							if(x+i > WorldRenderer.focus_x-2 && x+i < WorldRenderer.focus_x+2){
								if(z+k > WorldRenderer.focus_z-2 && z+k < WorldRenderer.focus_z+2){
									if(j > WorldRenderer.focus_y-2 && j < WorldRenderer.focus_y+2){
										if(!Blocks.isLiquid(bid)){
											sides = 0xff;
										}
									}
								}
							}
						}
						
						if(DangerZone.view_ores && dist < 4){
							//drawing dirt and sand blows it up! Too many...
							if(bid != Blocks.dirt.blockID && bid != Blocks.sand.blockID){
								if(Ores.isOre(bid))sides = 0xff;
							}
						}
						
						//double-check sides for liquids. We may have to display the top...
						if(Blocks.isLiquid(bid)){							
							if(nextleveldata == null || !Blocks.isLiquid(nextleveldata[i*16+k])){							
								if((meta&0x0f) != 0){
									sides |= 0x20;
								}
							}
						}

						if(sides != 0){ //Draw only the sides we need to!
							drew_something = true;
							focused = false;
							if(j == WorldRenderer.focus_y){
								if(x + i == WorldRenderer.focus_x){
									if(z + k == WorldRenderer.focus_z){
										focused = true;
									}
								}
							}

							if(lightmap != null){
								setVBOBrightness(lightmap[i*16+k]);
							}

							if(Blocks.renderAllSides(bid))sides = 0xff;
							
							//normal block drawing							
							if(!focused || (focused && WorldRenderer.focus_damage == 0)){									
								if(Blocks.hasOwnRenderer(bid)){
									Blocks.renderMeToVBO(c.VBOids, DangerZone.wr, world, pd, x+i, j, z+k, bid, meta, sides, focused,
											i*blockrenderwidth, j*blockrenderwidth, k*blockrenderwidth);								
								}else{
									//Special processing for liquids
									if(Blocks.isLiquid(bid)){
										float brfl, brfr, brbl, brbr;
										int xbid;
										int xcount = 1;
										boolean checkit = false;
										
										brfl = brfr = brbl = brbr = (meta&0x0f);
										
										if((meta&0x0f)!=0)checkit = true;
										if((sides & 0x20) == 0x20){
											if(Blocks.alwaystick(bid)){ //this to filter OUT non-ticking water!
												checkit = true;
											}
										}
										
										if(checkit){
											//first, calculate where corners SHOULD be, IFF there are no liquids higher around us
											//take the average of us and the three adjoining
											//brfl
											xbid = world.chunkcache.getBlock(world, pd, x+i-1,j,z+k);
											if(Blocks.isLiquid(xbid)){
												brfl += world.chunkcache.getBlockmeta(world, pd, x+i-1,j,z+k)&0x0f;
												xcount++;
											}											
											xbid = world.chunkcache.getBlock(world, pd, x+i-1,j,z+k+1);
											if(Blocks.isLiquid(xbid)){
												brfl += world.chunkcache.getBlockmeta(world, pd, x+i-1,j,z+k+1)&0x0f;
												xcount++;
											}	
											xbid = world.chunkcache.getBlock(world, pd, x+i,j,z+k+1);
											if(Blocks.isLiquid(xbid)){
												brfl += world.chunkcache.getBlockmeta(world, pd, x+i,j,z+k+1)&0x0f;
												xcount++;
											}	
											brfl /= xcount;
											if(brfl > 0x0f)brfl = 0x0f;
											//brfr
											xcount = 1;
											xbid = world.chunkcache.getBlock(world, pd, x+i+1,j,z+k);
											if(Blocks.isLiquid(xbid)){
												brfr += world.chunkcache.getBlockmeta(world, pd, x+i+1,j,z+k)&0x0f;
												xcount++;
											}	
											xbid = world.chunkcache.getBlock(world, pd, x+i+1,j,z+k+1);
											if(Blocks.isLiquid(xbid)){
												brfr += world.chunkcache.getBlockmeta(world, pd, x+i+1,j,z+k+1)&0x0f;
												xcount++;
											}	
											xbid = world.chunkcache.getBlock(world, pd, x+i,j,z+k+1);
											if(Blocks.isLiquid(xbid)){
												brfr += world.chunkcache.getBlockmeta(world, pd, x+i,j,z+k+1)&0x0f;
												xcount++;
											}	
											brfr /= xcount;
											if(brfr > 0x0f)brfr = 0x0f;
											//brbl
											xcount = 1;
											xbid = world.chunkcache.getBlock(world, pd, x+i-1,j,z+k);
											if(Blocks.isLiquid(xbid)){
												brbl += world.chunkcache.getBlockmeta(world, pd, x+i-1,j,z+k)&0x0f;
												xcount++;
											}	
											xbid = world.chunkcache.getBlock(world, pd, x+i-1,j,z+k-1);
											if(Blocks.isLiquid(xbid)){
												brbl += world.chunkcache.getBlockmeta(world, pd, x+i-1,j,z+k-1)&0x0f;
												xcount++;
											}	
											xbid = world.chunkcache.getBlock(world, pd, x+i,j,z+k-1);
											if(Blocks.isLiquid(xbid)){
												brbl += world.chunkcache.getBlockmeta(world, pd, x+i,j,z+k-1)&0x0f;
												xcount++;
											}	
											brbl /= xcount;
											if(brbl > 0x0f)brbl = 0x0f;
											//brbr
											xcount = 1;
											xbid = world.chunkcache.getBlock(world, pd, x+i+1,j,z+k);
											if(Blocks.isLiquid(xbid)){
												brbr += world.chunkcache.getBlockmeta(world, pd, x+i+1,j,z+k)&0x0f;
												xcount++;
											}	
											xbid = world.chunkcache.getBlock(world, pd, x+i+1,j,z+k-1);
											if(Blocks.isLiquid(xbid)){
												brbr += world.chunkcache.getBlockmeta(world, pd, x+i+1,j,z+k-1)&0x0f;
												xcount++;
											}	
											xbid = world.chunkcache.getBlock(world, pd, x+i,j,z+k-1);
											if(Blocks.isLiquid(xbid)){
												brbr += world.chunkcache.getBlockmeta(world, pd, x+i,j,z+k-1)&0x0f;
												xcount++;
											}	
											brbr /= xcount;
											if(brbr > 0x0f)brbr = 0x0f;
											
											//Now go back and check the four sides to see if we need to pull up to cover...
											if(brfl!=0 || brbl!=0){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i-1,j,z+k))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i-1,j+1,z+k))){
														brfl = brbl = 0; //pull up to cover the side!
													}
												}
											}
											if(brfr!=0 || brbr!=0){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i+1,j,z+k))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i+1,j+1,z+k))){
														brfr = brbr = 0; //pull up to cover the side!
													}
												}
											}
											if(brbl!=0 || brbr!=0){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i,j,z+k-1))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i,j+1,z+k-1))){
														brbl = brbr = 0; //pull up to cover the side!
													}
												}
											}
											if(brfl!=0 || brfr!=0){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i,j,z+k+1))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i,j+1,z+k+1))){
														brfl = brfr = 0; //pull up to cover the side!
													}
												}
											}
											
											//and no. we're not done yet. more pain. check the four diagonals too...
											if(brfl!=0 ){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i-1,j,z+k+1))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i-1,j+1,z+k+1))){
														brfl = 0; //pull up to cover the side!
													}
												}
											}
											if(brfr!=0 ){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i+1,j,z+k+1))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i+1,j+1,z+k+1))){
														brfr = 0; //pull up to cover the side!
													}
												}
											}
											if(brbl!=0 ){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i-1,j,z+k-1))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i-1,j+1,z+k-1))){
														brbl = 0; //pull up to cover the side!
													}
												}
											}
											if(brbr!=0 ){
												//if we are next to a liquid
												if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i+1,j,z+k-1))){
													//and there is one on top of it
													if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i+1,j+1,z+k-1))){
														brbr = 0; //pull up to cover the side!
													}
												}
											}
											//and one more... if a liquid on top, draw all side high!
											if(Blocks.isLiquid(world.chunkcache.getBlock(world, pd, x+i,j+1,z+k))){
												brfl = brfr = brbl = brbr =  0; //pull up to cover the side!
											}
										}
					
										drawLiquidTexturedCubeToVBO(c.VBOids, sides, bid, meta, i*blockrenderwidth, j*blockrenderwidth, k*blockrenderwidth, brfl, brfr, brbl, brbr, Blocks.isTranslucentForRender(bid));										
									}else{
										drawTexturedCubeToVBO(c.VBOids, sides, bid, meta, i*blockrenderwidth, j*blockrenderwidth, k*blockrenderwidth);
									}
								}
							}
						}
					//}else{
					//	if(bid != 0)System.out.printf("bad block value %d\n", bid);
					}
				}
			}
			
			if(drew_something){
				c.drawn[j] = 1;
			}else{
				c.drawn[j] = 0;
			}
		}
		c.redraw = 0;

		boolean doitagain = false;

		WorldRenderer.VBOlistlock.lock();
		for(itemp=0;itemp<=20;itemp++){
			if(c.VBOids[itemp] <= 0)break;
			v = WorldRenderer.VBOmap.get(c.VBOids[itemp]);
			if(v != null){
				if(dist > 8){ //give a little help to the graphics by telling it distance!
					v.isfar = true;
				}else{
					v.isfar = false;
				}
				if(v.finishDraw()){
					doitagain = true;
				}
			}
		}
		WorldRenderer.VBOlistlock.unlock();
		if(!doitagain)take_a_break = true;
		return doitagain;
	}
	 
	private boolean shouldRenderSide(int bid, boolean thisIsSolid, int thatbid){
		if(thatbid == 0)return true;
		boolean thatIsSolid = Blocks.isSolidForRender(thatbid);
		//boolean thatIsSolid = Blocks.BlockArray[thatbid].isSolidForRendering;
		if(thisIsSolid && thatIsSolid)return false;
		if(thisIsSolid && !thatIsSolid)return true;
		if(!thisIsSolid && !thatIsSolid && bid == thatbid)return false;
		if(!thisIsSolid && thatIsSolid)return false;
		if(Blocks.isLiquid(bid)&&Blocks.isLiquid(thatbid))return false;
		return true;
	}
	
	public void drawTexturedCubeToVBO(long chunkvbos[], int sides, int bid, int meta, int xo, int yo, int zo) {
		
		boolean tr = Blocks.isTranslucentForRender(bid);
	
		//generic block, rotated
		if((meta & 0xfc00) != 0){
			drawRotatedTexturedCubeToVBO(chunkvbos, sides, bid, meta, xo, yo, zo, tr);
			return;
		}
		
		//generic block
		VBOBuffer v = null;
		StitchedTexture st = null;
		float brw = blockrenderwidth/2;
		if(Blocks.renderSmaller(bid))brw -= 0.01f;
			
		if((sides & 0x20) != 0){
			st = findVBOtextureforblockside(0, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmin, cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);		
				v.addVertexInfoToVBO(-brw + xo, brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmin, cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);		
				v.addVertexInfoToVBO(-brw + xo, brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmax, cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);
				v.addVertexInfoToVBO(brw + xo, brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmax, cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);
			}
		}
		if((sides & 0x10) != 0){
			st = findVBOtextureforblockside(5, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmin, cbr*0.60f, cbg*0.60f, cbb*0.60f); 			
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmin, cbr*0.60f, cbg*0.60f, cbb*0.60f); 			
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmax, cbr*0.60f, cbg*0.60f, cbb*0.60f); 			
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmax, cbr*0.60f, cbg*0.60f, cbb*0.60f);
			}
		}
		if((sides & 0x08) != 0){
			st = findVBOtextureforblockside(1, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmin, cbr*sunposleft, cbg*sunposleft, cbb*sunposleft); 	
				v.addVertexInfoToVBO(-brw + xo, brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmin, cbr*sunposleft, cbg*sunposleft, cbb*sunposleft); 		
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmax, cbr*sunposleft, cbg*sunposleft, cbb*sunposleft); 		
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmax, cbr*sunposleft, cbg*sunposleft, cbb*sunposleft);
			}
		}
		if((sides & 0x04) != 0){
			st = findVBOtextureforblockside(2, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(-brw + xo, brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmin, cbr*sunposright, cbg*sunposright, cbb*sunposright); 
				v.addVertexInfoToVBO(brw + xo, brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmin, cbr*sunposright, cbg*sunposright, cbb*sunposright); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmax, cbr*sunposright, cbg*sunposright, cbb*sunposright); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmax, cbr*sunposright, cbg*sunposright, cbb*sunposright); 
			}
		}
		if((sides & 0x01) != 0){
			st = findVBOtextureforblockside(3, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(-brw + xo, brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmin, cbr*0.90f, cbg*0.90f, cbb*0.90f);
				v.addVertexInfoToVBO(-brw + xo, brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmin, cbr*0.90f, cbg*0.90f, cbb*0.90f); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmax, cbr*0.90f, cbg*0.90f, cbb*0.90f); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmax, cbr*0.90f, cbg*0.90f, cbb*0.90f);
			}
		}		
		if((sides & 0x02) != 0){
			st = findVBOtextureforblockside(4, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmin, cbr*0.80f, cbg*0.80f, cbb*0.80f); 
				v.addVertexInfoToVBO(brw + xo, brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmin, cbr*0.80f, cbg*0.80f, cbb*0.80f); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmax, cbr*0.80f, cbg*0.80f, cbb*0.80f); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmax, cbr*0.80f, cbg*0.80f, cbb*0.80f); 
			}
		}
		
	}
	
	public void drawLiquidTexturedCubeToVBO(long chunkvbos[], int sides, int bid, int meta, int xo, int yo, int zo, float inbrfl, float inbrfr, float inbrbl, float inbrbr, boolean tr) {
				
		VBOBuffer v = null;
		StitchedTexture st = null;
		int brw = blockrenderwidth/2;
		float brfl, brfr, brbl, brbr;
		
		brfl = brw - inbrfl;
		brfr = brw - inbrfr;
		brbl = brw - inbrbl;
		brbr = brw - inbrbr;			
			
		if((sides & 0x20) != 0){
			st = findVBOtextureforblockside(0, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brbr + yo, -brw + zo, st.xoffsetmax, st.yoffsetmin, cbr, cbg, cbb);		//top
				v.addVertexInfoToVBO(-brw + xo, brbl + yo, -brw + zo, st.xoffsetmin, st.yoffsetmin, cbr, cbg, cbb);		
				v.addVertexInfoToVBO(-brw + xo, brfl + yo, brw + zo, st.xoffsetmin, st.yoffsetmax, cbr, cbg, cbb);
				v.addVertexInfoToVBO(brw + xo, brfr + yo, brw + zo, st.xoffsetmax, st.yoffsetmax, cbr, cbg, cbb);
			}
		}
		if((sides & 0x10) != 0){
			st = findVBOtextureforblockside(5, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmin, cbr, cbg, cbb); 		//bottom	
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmin, cbr, cbg, cbb); 			
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmax, cbr, cbg, cbb); 			
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmax, cbr, cbg, cbb);
			}
		}
		if((sides & 0x08) != 0){
			st = findVBOtextureforblockside(1, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brfr + yo, brw + zo, st.xoffsetmax, st.yoffsetmin, cbr, cbg, cbb); 	//front
				v.addVertexInfoToVBO(-brw + xo, brfl + yo, brw + zo, st.xoffsetmin, st.yoffsetmin, cbr, cbg, cbb); 		
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmax, cbr, cbg, cbb); 		
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmax, cbr, cbg, cbb);
			}
		}
		if((sides & 0x04) != 0){
			st = findVBOtextureforblockside(2, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(-brw + xo, brbl + yo, -brw + zo, st.xoffsetmax, st.yoffsetmin, cbr, cbg, cbb); 	//back
				v.addVertexInfoToVBO(brw + xo, brbr + yo, -brw + zo, st.xoffsetmin, st.yoffsetmin, cbr, cbg, cbb); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmax, cbr, cbg, cbb); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmax, cbr, cbg, cbb); 
			}
		}
		if((sides & 0x01) != 0){
			st = findVBOtextureforblockside(3, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(-brw + xo, brfl + yo, brw + zo, st.xoffsetmax, st.yoffsetmin, cbr, cbg, cbb);	//left
				v.addVertexInfoToVBO(-brw + xo, brbl + yo, -brw + zo, st.xoffsetmin, st.yoffsetmin, cbr, cbg, cbb); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, st.xoffsetmin, st.yoffsetmax, cbr, cbg, cbb); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, st.xoffsetmax, st.yoffsetmax, cbr, cbg, cbb);
			}
		}		
		if((sides & 0x02) != 0){
			st = findVBOtextureforblockside(4, bid);
			v = findOrMakeVBOForTexture(chunkvbos, st, tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brbr + yo, -brw + zo, st.xoffsetmax, st.yoffsetmin, cbr, cbg, cbb); //right
				v.addVertexInfoToVBO(brw + xo, brfr + yo, brw + zo, st.xoffsetmin, st.yoffsetmin, cbr, cbg, cbb); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, st.xoffsetmin, st.yoffsetmax, cbr, cbg, cbb); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, st.xoffsetmax, st.yoffsetmax, cbr, cbg, cbb); 
			}
		}
		
	}
	
	private void rotate90(float coords[]){
		float tmp1, tmp2;
		tmp1 = coords[7];
		tmp2 = coords[6];
		coords[7] = coords[5];
		coords[6] = coords[4];
		coords[5] = coords[3];
		coords[4] = coords[2];
		coords[3] = coords[1];
		coords[2] = coords[0];
		coords[1] = tmp1;
		coords[0] = tmp2;
	}
	private void rotate180(float coords[]){
		rotate90(coords);
		rotate90(coords);
	}
	private void rotate270(float coords[]){
		float tmp1, tmp2;
		tmp1 = coords[0];
		tmp2 = coords[1];
		coords[0] = coords[2];
		coords[1] = coords[3];
		coords[2] = coords[4];
		coords[3] = coords[5];
		coords[4] = coords[6];
		coords[5] = coords[7];
		coords[6] = tmp1;
		coords[7] = tmp2;
	}
	
	/*
	 * Perform block rotation the HARD way. By switching sides and textures around.
	 */
	public void drawRotatedTexturedCubeToVBO(long chunkvbos[], int sides, int bid, int meta, int xo, int yo, int zo, boolean tr) {
		VBOBuffer v = null;
		int stp = 0;
		int sbm = 5;
		int sf = 1;
		int sb = 2;
		int sl = 3;
		int sr = 4;
		int tmp;

		for(tmp=0;tmp<6;tmp++){
			rot_st[tmp] = findVBOtextureforblockside(tmp, bid);
			tcoords[tmp][0] = rot_st[tmp].xoffsetmax;
			tcoords[tmp][1] = rot_st[tmp].yoffsetmin;
			tcoords[tmp][2] = rot_st[tmp].xoffsetmin;
			tcoords[tmp][3] = rot_st[tmp].yoffsetmin;
			tcoords[tmp][4] = rot_st[tmp].xoffsetmin;
			tcoords[tmp][5] = rot_st[tmp].yoffsetmax;
			tcoords[tmp][6] = rot_st[tmp].xoffsetmax;
			tcoords[tmp][7] = rot_st[tmp].yoffsetmax;
		}

/*
 * This really really really really really really really really really really really really really sucks....
 */
		if((meta&0xc000) == 0x0000){ //x
			if((meta&0x3000) == 0x0000){ //y
				if((meta&0x0c00) == 0x0000){ //z
					//done (shouldn't happen)
				}else if((meta&0x0c00) == 0x0400){
					stp = 4; 
					sbm = 3;
					sf = 1;
					sb = 2;
					sr = 5;
					sl = 0;
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);
					rotate90(tcoords[0]);
					rotate90(tcoords[5]);
					rotate90(tcoords[3]);
					rotate90(tcoords[4]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 5; 
					sbm = 0;
					sf = 1;
					sb = 2;
					sr = 3;
					sl = 4;
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);
					rotate180(tcoords[0]);
					rotate180(tcoords[5]);
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 3; 
					sbm = 4;
					sf = 1;
					sb = 2;
					sr = 0;
					sl = 5;
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);
					rotate270(tcoords[0]);
					rotate270(tcoords[5]);
					rotate270(tcoords[3]);
					rotate270(tcoords[4]);
				}			
			}else if((meta&0x3000) == 0x1000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 0; 
					sbm = 5;
					sf = 3;
					sb = 4;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					rotate90(tcoords[5]);
				}else if((meta&0x0c00) == 0x0400){
					stp = 4; 
					sbm = 3;
					sf = 0;
					sb = 5;
					sr = 1;
					sl = 2;
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);
					rotate90(tcoords[0]);
					rotate90(tcoords[5]);
					//rotate180(tcoords[3]);
					rotate180(tcoords[4]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 5; 
					sbm = 0;
					sf = 4;
					sb = 3;
					sr = 1;
					sl = 2;
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);
					rotate90(tcoords[0]);
					rotate270(tcoords[5]);
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 3; 
					sbm = 4;
					sf = 5;
					sb = 0;
					sr = 1;
					sl = 2;
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);
					rotate270(tcoords[0]);
					rotate270(tcoords[5]);
					//rotate180(tcoords[3]);
					rotate180(tcoords[4]);
				}		
			}else if((meta&0x3000) == 0x2000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 0; 
					sbm = 5;
					sf = 2;
					sb = 1;
					sr = 3;
					sl = 4;
					rotate180(tcoords[0]);
					rotate180(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 4; 
					sbm = 3;
					sf = 2;
					sb = 1;
					sr = 0;
					sl = 5;
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);
					rotate90(tcoords[0]);
					rotate90(tcoords[5]);
					rotate270(tcoords[3]);
					rotate270(tcoords[4]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 5; 
					sbm = 0;
					sf = 2;
					sb = 1;
					sr = 4;
					sl = 3;
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);
					//rotate180(tcoords[0]);
					//rotate90(tcoords[5]);
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 3; 
					sbm = 4;
					sf = 2;
					sb = 1;
					sr = 5;
					sl = 0;
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);
					rotate270(tcoords[0]);
					rotate270(tcoords[5]);
					rotate90(tcoords[3]);
					rotate90(tcoords[4]);
				}		
			}else if((meta&0x3000) == 0x3000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 0; 
					sbm = 5;
					sf = 4;
					sb = 3;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate270(tcoords[5]);
				}else if((meta&0x0c00) == 0x0400){
					stp = 4; 
					sbm = 3;
					sf = 5;
					sb = 0;
					sr = 2;
					sl = 1;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate180(tcoords[3]);
					//rotate90(tcoords[4]);
					rotate90(tcoords[5]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 5; 
					sbm = 0;
					sf = 3;
					sb = 4;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate90(tcoords[5]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 3; 
					sbm = 0;
					sf = 0;
					sb = 5;
					sr = 2;
					sl = 3;
					rotate270(tcoords[0]);
					rotate180(tcoords[1]);
					rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate270(tcoords[5]);
				}		
			}			
		}else if((meta&0xc000) == 0x4000){//twist on x
			if((meta&0x3000) == 0x0000){ //y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 2; 
					sbm = 1;
					sf = 0;
					sb = 5;
					sr = 4;
					sl = 3;
					//rotate270(tcoords[0]);
					//rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}else if((meta&0x0c00) == 0x0400){
					stp = 2; 
					sbm = 1;
					sf = 4;
					sb = 3;
					sr = 5;
					sl = 0;
					//rotate270(tcoords[0]);
					rotate90(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 2; 
					sbm = 1;
					sf = 5;
					sb = 0;
					sr = 3;
					sl = 4;
					//rotate270(tcoords[0]);
					rotate180(tcoords[1]);
					//rotate90(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 2; 
					sbm = 1;
					sf = 3;
					sb = 4;
					sr = 0;
					sl = 5;
					//rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}			
			}else if((meta&0x3000) == 0x1000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 4; 
					sbm = 3;
					sf = 0;
					sb = 5;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					//rotate270(tcoords[3]);
					rotate180(tcoords[4]);
					rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 5; 
					sbm = 0;
					sf = 4;
					sb = 3;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 3; 
					sbm = 4;
					sf = 5;
					sb = 0;
					sr = 1;
					sl = 2;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0c00){
					stp = 0; 
					sbm = 5;
					sf = 3;
					sb = 4;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					//rotate270(tcoords[1]);
					//rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate270(tcoords[5]);	
				}		
			}else if((meta&0x3000) == 0x2000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 1; 
					sbm = 2;
					sf = 0;
					sb = 5;
					sr = 3;
					sl = 4;
					rotate180(tcoords[0]);
					rotate180(tcoords[1]);
					//rotate90(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 1; 
					sbm = 2;
					sf = 4;
					sb = 3;
					sr = 0;
					sl = 5;
					rotate180(tcoords[0]);
					rotate270(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 1; 
					sbm = 2;
					sf = 5;
					sb = 0;
					sr = 4;
					sl = 3;
					rotate180(tcoords[0]);
					//rotate270(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0c00){
					stp = 1; 
					sbm = 2;
					sf = 3;
					sb = 4;
					sr = 5;
					sl = 0;
					rotate180(tcoords[0]);
					rotate90(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate270(tcoords[5]);	
				}		
			}else if((meta&0x3000) == 0x3000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 3; 
					sbm = 4;
					sf = 0;
					sb = 5;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate180(tcoords[3]);
					//rotate270(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 0; 
					sbm = 5;
					sf = 4;
					sb = 3;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					//rotate270(tcoords[1]);
					//rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					//rotate270(tcoords[4]);
					rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 4; 
					sbm = 3;
					sf = 5;
					sb = 0;
					sr = 2;
					sl = 1;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate180(tcoords[3]);
					//rotate270(tcoords[4]);
					rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0c00){
					stp = 5; 
					sbm = 0;
					sf = 3;
					sb = 4;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate90(tcoords[5]);	
				}		
			}		
		}else if((meta&0xc000) == 0x8000){//twist on x - 2
			if((meta&0x3000) == 0x0000){ //y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 5; 
					sbm = 0;
					sf = 2;
					sb = 1;
					sr = 4;
					sl = 3;
					//rotate270(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					//rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 3; 
					sbm = 4;
					sf = 2;
					sb = 1;
					sr = 5;
					sl = 0;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate90(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 0; 
					sbm = 5;
					sf = 2;
					sb = 1;
					sr = 3;
					sl = 4;
					rotate180(tcoords[0]);
					//rotate180(tcoords[1]);
					//rotate180(tcoords[2]);				
					//rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate180(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0c00){
					stp = 4; 
					sbm = 3;
					sf = 2;
					sb = 1;
					sr = 0;
					sl = 5;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate270(tcoords[4]);
					rotate90(tcoords[5]);	
				}			
			}else if((meta&0x3000) == 0x1000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 5; 
					sbm = 0;
					sf = 4;
					sb = 3;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate270(tcoords[5]);		
				}else if((meta&0x0c00) == 0x0400){
					stp = 3; 
					sbm = 4;
					sf = 5;
					sb = 0;
					sr = 1;
					sl = 2;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 0; 
					sbm = 5;
					sf = 3;
					sb = 4;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					//rotate270(tcoords[1]);
					//rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0c00){
					stp = 4; 
					sbm = 3;
					sf = 0;
					sb = 5;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					//rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate90(tcoords[5]);	
				}		
			}else if((meta&0x3000) == 0x2000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 5; 
					sbm = 0;
					sf = 1;
					sb = 2;
					sr = 3;
					sl = 4;
					rotate180(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate180(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 3; 
					sbm = 4;
					sf = 1;
					sb = 2;
					sr = 0;
					sl = 5;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate270(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 0; 
					sbm = 5;
					sf = 1;
					sb = 2;
					sr = 4;
					sl = 3;
					//rotate270(tcoords[0]);
					//rotate270(tcoords[1]);
					//rotate90(tcoords[2]);				
					//rotate270(tcoords[3]);
					//rotate270(tcoords[4]);
					//rotate270(tcoords[5]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 4; 
					sbm = 3;
					sf = 1;
					sb = 2;
					sr = 5;
					sl = 0;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate90(tcoords[4]);
					rotate90(tcoords[5]);	
				}		
			}else if((meta&0x3000) == 0x3000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 5; 
					sbm = 0;
					sf = 3;
					sb = 4;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 3; 
					sbm = 4;
					sf = 0;
					sb = 5;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate270(tcoords[5]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 0; 
					sbm = 5;
					sf = 4;
					sb = 3;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					//rotate270(tcoords[1]);
					//rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate90(tcoords[5]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 4; 
					sbm = 3;
					sf = 5;
					sb = 0;
					sr = 2;
					sl = 1;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate90(tcoords[5]);	
				}		
			}
		}else if((meta&0xc000) == 0xc000){//twist on x
			if((meta&0x3000) == 0x0000){ //y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 1; 
					sbm = 2;
					sf = 5;
					sb = 0;
					sr = 4;
					sl = 3;
					rotate180(tcoords[0]);
					//rotate90(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 1; 
					sbm = 2;
					sf = 3;
					sb = 4;
					sr = 5;
					sl = 0;
					rotate180(tcoords[0]);
					rotate90(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 1; 
					sbm = 2;
					sf = 0;
					sb = 5;
					sr = 3;
					sl = 4;
					rotate180(tcoords[0]);
					rotate180(tcoords[1]);
					//rotate90(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate90(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0c00){
					stp = 1; 
					sbm = 2;
					sf = 4;
					sb = 3;
					sr = 0;
					sl = 5;
					rotate180(tcoords[0]);
					rotate270(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate90(tcoords[3]);
					rotate270(tcoords[4]);
					//rotate90(tcoords[5]);	
				}			
			}else if((meta&0x3000) == 0x1000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 3; 
					sbm = 4;
					sf = 5;
					sb = 0;
					sr = 1;
					sl = 2;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					//rotate90(tcoords[3]);
					rotate180(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0400){
					stp = 0; 
					sbm = 5;
					sf = 3;
					sb = 4;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					//rotate270(tcoords[1]);
					//rotate90(tcoords[2]);				
					//rotate90(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate270(tcoords[5]);	
				}else if((meta&0x0c00) == 0x0800){
					stp = 4; 
					sbm = 3;
					sf = 0;
					sb = 5;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					//rotate90(tcoords[3]);
					rotate180(tcoords[4]);
					rotate90(tcoords[5]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 5; 
					sbm = 0;
					sf = 4;
					sb = 3;
					sr = 1;
					sl = 2;
					rotate90(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate270(tcoords[5]);
				}		
			}else if((meta&0x3000) == 0x2000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 2; 
					sbm = 1;
					sf = 5;
					sb = 0;
					sr = 3;
					sl = 4;
					//rotate90(tcoords[0]);
					rotate180(tcoords[1]);
					//rotate180(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}else if((meta&0x0c00) == 0x0400){
					stp = 2; 
					sbm = 1;
					sf = 3;
					sb = 4;
					sr = 0;
					sl = 5;
					//rotate90(tcoords[0]);
					rotate270(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 2; 
					sbm = 1;
					sf = 0;
					sb = 5;
					sr = 4;
					sl = 3;
					//rotate90(tcoords[0]);
					//rotate270(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 2; 
					sbm = 1;
					sf = 4;
					sb = 3;
					sr = 5;
					sl = 0;
					//rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate270(tcoords[3]);
					rotate90(tcoords[4]);
					rotate180(tcoords[5]);
				}		
			}else if((meta&0x3000) == 0x3000){//twist on Y
				if((meta&0x0c00) == 0x0000){ //z
					stp = 4; 
					sbm = 3;
					sf = 5;
					sb = 0;
					sr = 2;
					sl = 1;
					rotate90(tcoords[0]);
					rotate90(tcoords[1]);
					rotate270(tcoords[2]);				
					rotate180(tcoords[3]);
					//rotate90(tcoords[4]);
					rotate90(tcoords[5]);
				}else if((meta&0x0c00) == 0x0400){
					stp = 5; 
					sbm = 0;
					sf = 3;
					sb = 4;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate180(tcoords[1]);
					rotate180(tcoords[2]);				
					rotate180(tcoords[3]);
					rotate180(tcoords[4]);
					rotate90(tcoords[5]);
				}else if((meta&0x0c00) == 0x0800){
					stp = 3; 
					sbm = 4;
					sf = 0;
					sb = 5;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					rotate270(tcoords[1]);
					rotate90(tcoords[2]);				
					rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate270(tcoords[5]);
				}else if((meta&0x0c00) == 0x0c00){
					stp = 0; 
					sbm = 5;
					sf = 4;
					sb = 3;
					sr = 2;
					sl = 1;
					rotate270(tcoords[0]);
					//rotate270(tcoords[1]);
					//rotate90(tcoords[2]);				
					//rotate180(tcoords[3]);
					//rotate180(tcoords[4]);
					rotate90(tcoords[5]);
				}		
			}
		}

		float brw = blockrenderwidth/2;
		if(Blocks.renderSmaller(bid))brw -= 0.01f;
		
		if((sides & 0x20) != 0){
			//st = findVBOtextureforblockside(stp, bid);
			v = findOrMakeVBOForTexture(chunkvbos, rot_st[stp], tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brw + yo, -brw + zo, tcoords[stp][0], tcoords[stp][1], cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);		
				v.addVertexInfoToVBO(-brw + xo, brw + yo, -brw + zo, tcoords[stp][2], tcoords[stp][3], cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);		
				v.addVertexInfoToVBO(-brw + xo, brw + yo, brw + zo, tcoords[stp][4], tcoords[stp][5], cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);
				v.addVertexInfoToVBO(brw + xo, brw + yo, brw + zo, tcoords[stp][6], tcoords[stp][7], cbr*sunpostop, cbg*sunpostop, cbb*sunpostop);
			}
		}
		if((sides & 0x10) != 0){
			//st = findVBOtextureforblockside(sbm, bid);
			v = findOrMakeVBOForTexture(chunkvbos, rot_st[sbm], tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, tcoords[sbm][0], tcoords[sbm][1], cbr*0.60f, cbg*0.60f, cbb*0.60f); 			
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, tcoords[sbm][2], tcoords[sbm][3], cbr*0.60f, cbg*0.60f, cbb*0.60f); 			
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, tcoords[sbm][4], tcoords[sbm][5], cbr*0.60f, cbg*0.60f, cbb*0.60f); 			
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, tcoords[sbm][6], tcoords[sbm][7], cbr*0.60f, cbg*0.60f, cbb*0.60f);
			}
		}
		if((sides & 0x08) != 0){
			//st = findVBOtextureforblockside(sf, bid);
			v = findOrMakeVBOForTexture(chunkvbos, rot_st[sf], tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brw + yo, brw + zo, tcoords[sf][0], tcoords[sf][1], cbr*sunposleft, cbg*sunposleft, cbb*sunposleft); 	
				v.addVertexInfoToVBO(-brw + xo, brw + yo, brw + zo, tcoords[sf][2], tcoords[sf][3], cbr*sunposleft, cbg*sunposleft, cbb*sunposleft); 		
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, tcoords[sf][4], tcoords[sf][5], cbr*sunposleft, cbg*sunposleft, cbb*sunposleft); 		
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, tcoords[sf][6], tcoords[sf][7], cbr*sunposleft, cbg*sunposleft, cbb*sunposleft);
			}
		}
		if((sides & 0x04) != 0){
			//st = findVBOtextureforblockside(sb, bid);
			v = findOrMakeVBOForTexture(chunkvbos, rot_st[sb], tr);
			if(v != null){
				v.addVertexInfoToVBO(-brw + xo, brw + yo, -brw + zo, tcoords[sb][0], tcoords[sb][1], cbr*sunposright, cbg*sunposright, cbb*sunposright); 
				v.addVertexInfoToVBO(brw + xo, brw + yo, -brw + zo, tcoords[sb][2], tcoords[sb][3], cbr*sunposright, cbg*sunposright, cbb*sunposright); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, tcoords[sb][4], tcoords[sb][5], cbr*sunposright, cbg*sunposright, cbb*sunposright); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, tcoords[sb][6], tcoords[sb][7], cbr*sunposright, cbg*sunposright, cbb*sunposright); 
			}
		}
		if((sides & 0x01) != 0){
			//st = findVBOtextureforblockside(sl, bid);
			v = findOrMakeVBOForTexture(chunkvbos, rot_st[sl], tr);
			if(v != null){
				v.addVertexInfoToVBO(-brw + xo, brw + yo, brw + zo, tcoords[sl][0], tcoords[sl][1], cbr*0.90f, cbg*0.90f, cbb*0.90f);
				v.addVertexInfoToVBO(-brw + xo, brw + yo, -brw + zo, tcoords[sl][2], tcoords[sl][3], cbr*0.90f, cbg*0.90f, cbb*0.90f); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, -brw + zo, tcoords[sl][4], tcoords[sl][5], cbr*0.90f, cbg*0.90f, cbb*0.90f); 
				v.addVertexInfoToVBO(-brw + xo, -brw + yo, brw + zo, tcoords[sl][6], tcoords[sl][7], cbr*0.90f, cbg*0.90f, cbb*0.90f);
			}
		}		
		if((sides & 0x02) != 0){
			//st = findVBOtextureforblockside(sr, bid);
			v = findOrMakeVBOForTexture(chunkvbos, rot_st[sr], tr);
			if(v != null){
				v.addVertexInfoToVBO(brw + xo, brw + yo, -brw + zo, tcoords[sr][0], tcoords[sr][1], cbr*0.80f, cbg*0.80f, cbb*0.80f); 
				v.addVertexInfoToVBO(brw + xo, brw + yo, brw + zo, tcoords[sr][2], tcoords[sr][3], cbr*0.80f, cbg*0.80f, cbb*0.80f); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, brw + zo, tcoords[sr][4], tcoords[sr][5], cbr*0.80f, cbg*0.80f, cbb*0.80f); 
				v.addVertexInfoToVBO(brw + xo, -brw + yo, -brw + zo, tcoords[sr][6], tcoords[sr][7], cbr*0.80f, cbg*0.80f, cbb*0.80f); 
			}
		}
		
	}
	
	public static VBOBuffer findOrMakeVBOForTexture(long cvs[], StitchedTexture st, boolean translucent){
		
		//cheap and dirty quick-check!
		if(st == st_last && v_last != null && v_last.isTranslucent == translucent)return v_last;
		
		VBOBuffer v = null;
		int i;
		
		WorldRenderer.VBOlistlock.lock();
		for(i=0;i<20;i++){
			if(cvs[i] <= 0){ //not found. Make a new one.
				break;
			}
			//get it from the map
			v = WorldRenderer.VBOmap.get(cvs[i]);
			if(v != null){
				if(v.textureindex == st.texturesindex && translucent == v.isTranslucent){
					v_last = v;
					st_last = st;
					WorldRenderer.VBOlistlock.unlock();
					return v; //FOUND!
				}
			//}else{
			//	System.out.printf("existing vbo lookup fail\n");
			}
		}
		//if(i >= 20){
		//	WorldRenderer.VBOlistlock.unlock();
		//	System.out.printf("no chunkvbos space left for chunk... problem?\n");
		//	return null; //FULL?
		//}
		//Not found. Make a new VBO.
		v = new VBOBuffer();
		v.textureindex = st.texturesindex;
		v.VBOid = WorldRenderer.getNextVBOid();
		v.isTranslucent = translucent;
		WorldRenderer.VBOmap.put(v.VBOid, v); //add it to the map!
		WorldRenderer.vbocount++;
		cvs[i] = v.VBOid; //add it to the chunk
/*
			if(i == 1){
				if(v.isTranslucent != true){
					System.out.printf("vboindex 1 not translucent\n");
				}
			}
			if(i == 0){
				if(v.isTranslucent == true){
					System.out.printf("vboindex 0 translucent\n");
				}
			}
			if(i > 1){
				System.out.printf("vboindex unexpected: %d\n", i);
			}
*/
		v_last = v;
		st_last = st;
		WorldRenderer.VBOlistlock.unlock();
		return v;
	}
	
	public static StitchedTexture findVBOtextureforblockside(int side, int bid){		
		StitchedTexture st = Blocks.BlockArray[bid].getStitchedTexture(side);
		if(st.texturesindex < 0){
			//st = Blocks.BlockArray[1].getStitchedTexture(0); //default to stone!
			//THIS SHOULD ONLY HAPPEN FROM COLORING BLOCK!!!
			DangerZone.wr.oneblock = bid;
			while(DangerZone.wr.oneblock >= 0){
				Thread.yield();
			}
		}
		return st;
	}
	
	private void setVBOBrightness(float m){
		float flr, flg, flb;
		flr = brightness_red + m;
		if(flr < 0)flr = 0;
		if(flr > 1)flr = 1;
		flg = brightness_green + m;
		if(flg < 0)flg = 0;
		if(flg > 1)flg = 1;
		flb = brightness_blue + m;
		if(flb < 0)flb = 0;
		if(flb > 1)flb = 1;
		//GL11.glColor3f(flr, flg, flb);
		cbr = flr;
		cbg = flg;
		cbb = flb;
	}
	
	private void recalcBrightness(int d, int yp){			
		float f = WorldRendererUtils.getBrightnessForLevel(d, yp);
		if(f < 0)f = 0;
		if(f > 1)f = 1;
		brightness_red = brightness_green = brightness_blue = f;
		
		//FIXME TODO!!! There has to be another way to do this. This works, but is awful!
		//Chunks all have to get re-drawn in the right color. It's a mess when swimming!
		//Maybe there is an overall color mask/filter that can be set???
		//if(DangerZone.player.isInLiquid){
		//	if(Blocks.isLiquid(DangerZone.world.getblock(DangerZone.player.dimension, (int)DangerZone.player.posx, (int)(DangerZone.player.posy+DangerZone.player.eyeheight), (int)DangerZone.player.posz))){
		//		brightness_red /=2;
		//		brightness_green /=2;
		//	}
		//}
}
	
}