package com.plusminus.craft; | |
import org.lwjgl.opengl.GL11; | |
import com.plusminus.craft.dtf.ByteArrayTag; | |
import com.plusminus.craft.dtf.CompoundTag; | |
import com.plusminus.craft.dtf.IntTag; | |
import com.plusminus.craft.dtf.Tag; | |
import static com.plusminus.craft.MineCraftConstants.*; | |
public class Chunk { | |
private int displayListNum; | |
private int transparentListNum; | |
private int selectedDisplayListNum; | |
public int x; | |
public int z; | |
public boolean isDirty; | |
public boolean isSelectedDirty; | |
private CompoundTag chunkData; | |
private ByteArrayTag blockData; | |
private ByteArrayTag mapData; | |
private MinecraftLevel level; | |
public Chunk(Tag data, MinecraftLevel level) { | |
this.chunkData = (CompoundTag) data; | |
//System.out.println(this.chunkData); | |
//System.exit(0); | |
displayListNum = GL11.glGenLists(1); | |
selectedDisplayListNum = GL11.glGenLists(1); | |
transparentListNum = GL11.glGenLists(1); | |
CompoundTag levelTag = (CompoundTag) chunkData.value.get(0); // first tag | |
IntTag xPosTag = (IntTag) levelTag.getTagWithName("xPos"); | |
IntTag zPosTag = (IntTag) levelTag.getTagWithName("zPos"); | |
this.x = xPosTag.value; | |
this.z = zPosTag.value; | |
blockData = (ByteArrayTag) levelTag.getTagWithName("Blocks"); | |
mapData = (ByteArrayTag) levelTag.getTagWithName("Data"); | |
this.isDirty = true; | |
this.isSelectedDirty = true; | |
this.level = level; | |
//System.out.println(data); | |
//System.exit(0); | |
} | |
public CompoundTag getChunkData() { | |
return this.chunkData; | |
} | |
public ByteArrayTag getMapData() { | |
return this.blockData; | |
} | |
public void renderLeftRight(int t, float x, float y, float z) { | |
GL11.glBegin(GL11.GL_TRIANGLE_STRIP); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t], precalcSpriteSheetToTextureY[t]); | |
GL11.glVertex3f(x-0.5f, y+0.5f, z+0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t]+TEX16, precalcSpriteSheetToTextureY[t]); | |
GL11.glVertex3f(x-0.5f, y+0.5f, z-0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t],precalcSpriteSheetToTextureY[t]+TEX16); | |
GL11.glVertex3f(x-0.5f, y-0.5f, z+0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t]+TEX16, precalcSpriteSheetToTextureY[t]+TEX16); | |
GL11.glVertex3f(x-0.5f, y-0.5f, z-0.5f); | |
GL11.glEnd(); | |
} | |
public void renderTopDown(int t, float x, float y, float z) { | |
GL11.glBegin(GL11.GL_TRIANGLE_STRIP); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t], precalcSpriteSheetToTextureY[t]); | |
GL11.glVertex3f(x-0.5f, y-0.5f, z+0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t]+TEX16, precalcSpriteSheetToTextureY[t]); | |
GL11.glVertex3f(x-0.5f, y-0.5f, z-0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t], precalcSpriteSheetToTextureY[t]+TEX16); | |
GL11.glVertex3f(x+0.5f, y-0.5f, z+0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t]+TEX16, precalcSpriteSheetToTextureY[t]+TEX16); | |
GL11.glVertex3f(x+0.5f, y-0.5f, z-0.5f); | |
GL11.glEnd(); | |
} | |
public void renderFarNear(int t, float x, float y, float z) { | |
GL11.glBegin(GL11.GL_TRIANGLE_STRIP); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t], precalcSpriteSheetToTextureY[t]); | |
GL11.glVertex3f(x-0.5f, y+0.5f, z-0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t]+TEX16, precalcSpriteSheetToTextureY[t]); | |
GL11.glVertex3f(x+0.5f, y+0.5f, z-0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t], precalcSpriteSheetToTextureY[t]+TEX16); | |
GL11.glVertex3f(x-0.5f, y-0.5f, z-0.5f); | |
GL11.glTexCoord2f(precalcSpriteSheetToTextureX[t]+TEX16, precalcSpriteSheetToTextureY[t]+TEX16); | |
GL11.glVertex3f(x+0.5f, y-0.5f, z-0.5f); | |
GL11.glEnd(); | |
} | |
public boolean isInRange(float x, float y, float maxDistance) { | |
float realX = this.x*16; | |
float realY = this.z*16; | |
double distance = Math.sqrt(((x-realX) * (x-realX)) + ((y-realY) * (y-realY))); | |
return distance < maxDistance; | |
} | |
public byte getBlock(int x, int y, int z) { | |
return blockData.value[y + (z * 128) + (x * 128 * 16)]; | |
} | |
public byte getData(int x, int y, int z) { | |
int offset = y + (z * 128) + (x * 128 * 16); | |
int halfOffset = offset / 2; | |
if(offset % 2 == 0) { | |
return (byte) (mapData.value[halfOffset] & 0xF); | |
} else { | |
return (byte) (mapData.value[halfOffset] >> 4); | |
} | |
} | |
public boolean isSolid(byte i) { | |
if((i == 0) || (i == TYPE_WATER) || (i == TYPE_WATER_STATIONARY) || (i == TYPE_TORCH) || (i==TYPE_LAVA) || (i==TYPE_LAVA_STATIONARY)) { | |
return false; | |
} | |
return true; | |
} | |
public void renderTorch(int xxx, int yyy, int zzz) { | |
float x1 = 0, x2 = 0, z1 = 0, z2 = 0, yy = 0; | |
byte data = getData(xxx, yyy, zzz); | |
switch (data) { | |
case 1: | |
x1 -= 0.125; x2 -= 0.5; | |
yy = 3/16.0f; break; | |
case 2: | |
x1 += 0.125; x2 += 0.5; | |
yy = 3/16.0f; break; | |
case 3: | |
z1 -= 0.125; z2 -= 0.5; | |
yy = 3/16.0f; break; | |
case 4: | |
z1 += 0.125; z2 += 0.5; | |
yy = 3/16.0f; break; | |
} | |
//Light(chunk, x, y, z); | |
float x = xxx + this.x*16 -0.5f; | |
float z = zzz + this.z*16 -0.5f; | |
float y = yyy - 0.5f; | |
/* | |
* | |
* RectangleF rect = new RectangleF(x / 16.0f + 0.00004f, y / 16.0f + 0.00004f, | |
1 / 16.0f - 0.00008f, 1 / 16.0f - 0.00008f); | |
*/ | |
float bx,by; | |
float ex,ey; | |
bx = 0.0f+TEX64; | |
by = 5.0f / 16.0f; | |
ex = bx + TEX16-TEX32; | |
ey = by + TEX16; | |
// GL11.glDisable(GL11.GL_CULL_FACE); | |
//GL11.glDisable(GL11.GL_DEPTH_TEST); | |
GL11.glBegin(GL11.GL_QUADS); | |
GL11.glNormal3f(1.0f, 0.0f, 0.0f); | |
GL11.glTexCoord2f(bx, by); GL11.glVertex3f(x+x1+9/16.0f+TEX64, y+yy+1.0f, z+z1); | |
GL11.glTexCoord2f(ex, by); GL11.glVertex3f(x+x1+9/16.0f+TEX64, y+yy+1.0f, z+z1+1.0f); | |
GL11.glTexCoord2f(ex, ey); GL11.glVertex3f(x+x2+9/16.0f-TEX64, y+yy, z+z2+1.0f); | |
GL11.glTexCoord2f(bx, ey); GL11.glVertex3f(x+x2+9/16.0f-TEX64, y+yy, z+z2); | |
GL11.glNormal3f(-1.0f, 0.0f, 0.0f); | |
GL11.glTexCoord2f(bx, by); GL11.glVertex3f(x+x1+7/16.0f+TEX64, y+yy+1.0f, z+z1+1.0f); | |
GL11.glTexCoord2f(ex, by); GL11.glVertex3f(x+x1+7/16.0f+TEX64, y+yy+1.0f, z+z1); | |
GL11.glTexCoord2f(ex, ey); GL11.glVertex3f(x+x2+7/16.0f-TEX64, y+yy, z+z2); | |
GL11.glTexCoord2f(bx, ey); GL11.glVertex3f(x+x2+7/16.0f-TEX64, y+yy, z+z2+1.0f); | |
GL11.glNormal3f(0.0f, 0.0f, 1.0f); | |
GL11.glTexCoord2f(bx, by); GL11.glVertex3f(x+x1+1.0f, y+yy+1.0f, z+z1+9/16.0f+TEX64); | |
GL11.glTexCoord2f(ex, by); GL11.glVertex3f(x+x1, y+yy+1.0f, z+z1+9/16.0f+TEX64); | |
GL11.glTexCoord2f(ex, ey); GL11.glVertex3f(x+x2, y+yy, z+z2+9/16.0f-TEX64); | |
GL11.glTexCoord2f(bx, ey); GL11.glVertex3f(x+x2+1.0f, y+yy, z+z2+9/16.0f-TEX64); | |
GL11.glNormal3f(0.0f, 0.0f, -1.0f); | |
GL11.glTexCoord2f(bx, by); GL11.glVertex3f(x+x1, y+yy+1.0f, z+z1+7/16.0f+TEX64); | |
GL11.glTexCoord2f(ex, by); GL11.glVertex3f(x+x1+1.0f, y+yy+1.0f, z+z1+7/16.0f+TEX64); | |
GL11.glTexCoord2f(ex, ey); GL11.glVertex3f(x+x2+1.0f, y+yy, z+z2+7/16.0f-TEX64); | |
GL11.glTexCoord2f(bx, ey); GL11.glVertex3f(x+x2, y+yy, z+z2+7/16.0f-TEX64); | |
x1 *= 2.125f; z1 *= 2.125f; | |
GL11.glNormal3f(0.0f, 1.0f, 0.0f); | |
GL11.glTexCoord2f(bx+TEX128, by+TEX128); GL11.glVertex3f(x+x1+9/16.0f, y+yy+10/16.0f, z+z1+7/16.0f); | |
GL11.glTexCoord2f(ex-TEX128, by+TEX128); GL11.glVertex3f(x+x1+7/16.0f, y+yy+10/16.0f, z+z1+7/16.0f); | |
GL11.glTexCoord2f(ex-TEX128, ey-TEX32); GL11.glVertex3f(x+x1+7/16.0f, y+yy+10/16.0f, z+z1+9/16.0f); | |
GL11.glTexCoord2f(bx+TEX128, ey-TEX32); GL11.glVertex3f(x+x1+9/16.0f, y+yy+10/16.0f, z+z1+9/16.0f); | |
GL11.glEnd(); | |
//GL11.glEnable(GL11.GL_DEPTH_TEST); | |
//GL11.glEnable(GL11.GL_CULL_FACE); | |
} | |
public boolean checkSolid(byte block, boolean transpararency) { | |
if(block == 0) { | |
return true; | |
} | |
return isSolid(block) == transpararency; | |
} | |
public void renderWorld(boolean transparency, boolean render_bedrock, boolean onlySelected, boolean[] selectedMap) { | |
float worldX = this.x*16; | |
float worldZ = this.z*16; | |
for(int x=0;x<16;x++) { | |
int xOff = (x * 128 * 16); | |
for(int z=0;z<16;z++) { | |
int zOff = (z * 128); | |
int blockOffset = zOff + xOff-1; | |
for(int y=0;y<128;y++) { | |
blockOffset++; | |
byte t = blockData.value[blockOffset]; | |
if(t == 0) { | |
continue; | |
} | |
if(t == TYPE_TORCH) { | |
//System.out.println("Torch: " + getData(x,y,z)); | |
} | |
int textureId = blockDataToSpriteSheet[t]; | |
if(textureId == -1) { | |
//System.out.println("unknown block type: " + t); | |
continue; | |
} | |
if(transparency && isSolid(t)) { | |
continue; | |
} | |
if(!transparency && !isSolid(t)) { | |
continue; | |
} | |
//if(!transparency && !isSolid(t)) { | |
// continue; | |
//} | |
boolean draw = false; | |
if(!onlySelected) { | |
boolean above = true; | |
boolean below = true; | |
boolean left = true; | |
boolean right = true; | |
boolean near = true; | |
boolean far = true; | |
if (render_bedrock && textureId == MineCraftConstants.TEXTURE_BEDROCK) | |
{ | |
// This block of code was more or less copied/modified directly from the "else" block | |
// below - should see if there's a way we can abstract this instead. Also, I suspect | |
// that this is where we'd fix water rendering... | |
// check above | |
if(y<127 && blockData.value[blockOffset+1] != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
above = false; | |
} | |
// check below | |
if(y>0 && blockData.value[blockOffset-1] != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
below = false; | |
} | |
// check left; | |
if(x>0 && blockData.value[blockOffset-BLOCKSPERCOLUMN] != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
left = false; | |
} else if(x==0 && this.x > -63) { | |
Chunk leftChunk = level.getChunk(this.x-1, this.z); | |
if(leftChunk != null && leftChunk.getBlock(15, y, z) != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
left = false; | |
} | |
} | |
// check right | |
if(x<15 && blockData.value[blockOffset+BLOCKSPERCOLUMN] != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
right = false; | |
} else if(x==15 && this.x < 63) { | |
Chunk rightChunk = level.getChunk(this.x+1,this.z); | |
if(rightChunk != null && rightChunk.getBlock(0, y, z) != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
right = false; | |
} | |
} | |
// check near | |
if(z>0 && blockData.value[blockOffset-BLOCKSPERROW] != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
near = false; | |
} else if(z==0 && this.z > -63) { | |
Chunk nearChunk = level.getChunk(this.x,this.z-1); | |
if(nearChunk != null && nearChunk.getBlock(x, y, 15) != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
near = false; | |
} | |
} | |
// check far | |
if(z<15 && blockData.value[blockOffset+BLOCKSPERROW] != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
far = false; | |
} else if(z==15 && this.z < 63) { | |
Chunk farChunk = level.getChunk(this.x,this.z+1); | |
if(farChunk != null && farChunk.getBlock(x, y, 0) != MineCraftConstants.BLOCK_BEDROCK) { | |
draw = true; | |
far = false; | |
} | |
} | |
} | |
else | |
{ | |
// check above | |
if(y<127 && checkSolid(blockData.value[blockOffset+1], transparency)) { | |
draw = true; | |
above = false; | |
} | |
// check below | |
if(y>0 && checkSolid(blockData.value[blockOffset-1], transparency)) { | |
draw = true; | |
below = false; | |
} | |
// check left; | |
if(x>0 && checkSolid(blockData.value[blockOffset-BLOCKSPERCOLUMN], transparency)) { | |
draw = true; | |
left = false; | |
} else if(x==0 && this.x > -63) { | |
Chunk leftChunk = level.getChunk(this.x-1, this.z); | |
if(leftChunk != null && checkSolid(leftChunk.getBlock(15, y, z), transparency)) { | |
draw = true; | |
left = false; | |
} | |
} | |
// check right | |
if(x<15 && checkSolid(blockData.value[blockOffset+BLOCKSPERCOLUMN], transparency)) { | |
draw = true; | |
right = false; | |
} else if(x==15 && this.x < 63) { | |
Chunk rightChunk = level.getChunk(this.x+1,this.z); | |
if(rightChunk != null && checkSolid(rightChunk.getBlock(0, y, z), transparency)) { | |
draw = true; | |
right = false; | |
} | |
} | |
// check near | |
if(z>0 && checkSolid(blockData.value[blockOffset-BLOCKSPERROW], transparency)) { | |
draw = true; | |
near = false; | |
} else if(z==0 && this.z > -63) { | |
Chunk nearChunk = level.getChunk(this.x,this.z-1); | |
if(nearChunk != null && checkSolid(nearChunk.getBlock(x, y, 15), transparency)) { | |
draw = true; | |
near = false; | |
} | |
} | |
// check far | |
if(z<15 && checkSolid(blockData.value[blockOffset+BLOCKSPERROW], transparency)) { | |
draw = true; | |
far = false; | |
} else if(z==15 && this.z < 63) { | |
Chunk farChunk = level.getChunk(this.x,this.z+1); | |
if(farChunk != null && checkSolid(farChunk.getBlock(x, y, 0), transparency)) { | |
draw = true; | |
far = false; | |
} | |
} | |
} | |
if(t == TYPE_TORCH) { | |
renderTorch(x,y,z); | |
} else { | |
// if we have to draw this block | |
if(draw) { | |
if(!near) this.renderFarNear(textureId, worldX+x, y, worldZ+z); | |
if(!far) this.renderFarNear(textureId, worldX+x, y, worldZ+z+1); | |
if(!below) this.renderTopDown(textureId, worldX+x, y, worldZ+z); | |
if(!above) this.renderTopDown(textureId, worldX+x, y+1, worldZ+z); | |
if(!left) this.renderLeftRight(textureId, worldX+x, y, worldZ+z); | |
if(!right) this.renderLeftRight(textureId, worldX+x+1, y, worldZ+z); | |
} | |
} | |
} else { | |
draw = false; | |
for(int i=0;i<selectedMap.length;i++) { | |
if(selectedMap[i] && TEXTURE_ORES[i] == textureId) { | |
draw = true; | |
break; | |
} | |
} | |
if(draw) { | |
this.renderFarNear(textureId, worldX+x, y, worldZ+z); | |
this.renderFarNear(textureId, worldX+x, y, worldZ+z+1); | |
this.renderTopDown(textureId, worldX+x, y, worldZ+z); | |
this.renderTopDown(textureId, worldX+x, y+1, worldZ+z); | |
this.renderLeftRight(textureId, worldX+x, y, worldZ+z); | |
this.renderLeftRight(textureId, worldX+x+1, y, worldZ+z); | |
} | |
} | |
} | |
} | |
} | |
} | |
public void renderSolid(boolean render_bedrock) { | |
if(isDirty) { | |
GL11.glNewList(this.displayListNum, GL11.GL_COMPILE); | |
renderWorld(false, render_bedrock, false, null); | |
GL11.glEndList(); | |
GL11.glNewList(this.transparentListNum, GL11.GL_COMPILE); | |
renderWorld(true, false, false, null); | |
GL11.glEndList(); | |
this.isDirty = false; | |
} | |
GL11.glCallList(this.displayListNum); | |
} | |
public void renderTransparency() { | |
GL11.glCallList(this.transparentListNum); | |
} | |
public void renderSelected(boolean[] selectedMap) { | |
if(isSelectedDirty) { | |
GL11.glNewList(this.selectedDisplayListNum, GL11.GL_COMPILE); | |
renderWorld(false, false, true, selectedMap); | |
GL11.glEndList(); | |
this.isSelectedDirty = false; | |
} | |
GL11.glCallList(this.selectedDisplayListNum); | |
} | |
} |