package com.voxel.engine.core.Chunk; import com.voxel.engine.core.Block.Block; import com.voxel.engine.core.Noise.SimplexNoise; import org.lwjgl.opengl.GL11; import java.util.Random; import static org.lwjgl.opengl.GL11.*; /** * Created with IntelliJ IDEA. * User: Toby's PC * Date: 07/01/14 * Time: 19:25 */ public class Chunk implements ChunkProtocol{ private int chunkList = -1; public int maxHeight = 0; private int tx = 0; private int ty = 0; private int tz = 0; public static final int CHUNK_SIZE = 16; public Block[][][] blocks; private int xOffset = 0; private int yOffset = 0; private int zOffset = 0; private String key; public String getKey(){ return key; } public void setKey(String key){ this.key = key; } public int getX(){ return xOffset; } public int getY(){ return yOffset; } public int getZ(){ return xOffset; } public Block getBlock(int x, int y, int z){ return blocks[x][y][z]; } public int rebuildChunk(){ int count = 0; if(chunkList <= -1){ chunkList = glGenLists(1); } glNewList(chunkList, GL_COMPILE); count = createChunkList(); glEndList(); return count; } private int createChunkList(){ tx = 0; ty = 0; tz = 0; int iHidden = 0; int iBlockCount = 0; boolean bLeft = !false; boolean bRight = !false; boolean bAbove = !false; boolean bBelow = !false; boolean bFront = !false; boolean bBack = !false; boolean bDefault = true; glEnable(GL11.GL_CULL_FACE); glBegin(GL11.GL_QUADS); for(int x = 0;x < CHUNK_SIZE;x++){ for(int y = 0;y < CHUNK_SIZE;y++){ for(int z = 0;z < CHUNK_SIZE;z++){ if (!blocks[x][y][z].isActive()) { continue; } bLeft = bDefault; if (x > 0) { bLeft = blocks[x - 1][y][z].isActive(); } else bLeft = false; bRight = bDefault; if (x < Chunk.CHUNK_SIZE - 1) { bRight = blocks[x + 1][y][z].isActive(); } else bRight = false; bAbove = bDefault; if (y > 0) { bAbove = blocks[x][y - 1][z].isActive(); } else bAbove = false; bBelow = bDefault; if (y < Chunk.CHUNK_SIZE - 1) { bBelow = blocks[x][y + 1][z].isActive(); } else bBelow = false; bFront = bDefault; if (z > 0) { bFront = blocks[x][y][z - 1].isActive(); } else bFront = false; bBack = bDefault; if (z < Chunk.CHUNK_SIZE - 1) { bBack = blocks[x][y][z + 1].isActive(); } else bBack = false; boolean bResult = bLeft & bRight & bAbove & bBelow & bFront & bBack; if (!bResult) // Block is not hidden by neighbouring blocks { tx = ((xOffset * Chunk.CHUNK_SIZE)) + (x);// << 1); ty = ((yOffset * Chunk.CHUNK_SIZE)) + (y);// << 1); tz = ((zOffset * Chunk.CHUNK_SIZE)) + (z);// << 1); renderBlock(blocks[x][y][z].getType(), x, y, z); iBlockCount++; // total of blocks that can be seen } else iHidden++; // amount of blocks that are surrounded } } } glEnd(); glDisable(GL11.GL_CULL_FACE); return iBlockCount; } private void renderBlock(Block.BlockType type, int x, int y, int z) { // GL11.glDisable(GL_TEXTURE_2D); if (z <= Chunk.CHUNK_SIZE - 1) { // if (z != 0 && (z == Chunk.CHUNK_SIZE - 1) || (!blocks[x][y][z + 1].isActive())) { off_glVertex3f(-0.5f, -0.5f, 0.5f); off_glVertex3f(0.5f, -0.5f, 0.5f); off_glVertex3f(0.5f, 0.5f, 0.5f); off_glVertex3f(-0.5f, 0.5f, 0.5f); } } // Back Face if (z >= 0) { // if (z != Chunk.CHUNK_SIZE - 1 && (z == 0) || (!blocks[x][y][z - 1].isActive())) { off_glVertex3f(-0.5f, -0.5f, -0.5f); off_glVertex3f(-0.5f, 0.5f, -0.5f); off_glVertex3f(0.5f, 0.5f, -0.5f); off_glVertex3f(0.5f, -0.5f, -0.5f); } } // Top Face if (y <= Chunk.CHUNK_SIZE - 1) { // if (y != 0 && (y == Chunk.CHUNK_SIZE - 1) || (!blocks[x][y + 1][z].isActive())) { off_glVertex3f(-0.5f, 0.5f, -0.5f); off_glVertex3f(-0.5f, 0.5f, 0.5f); off_glVertex3f(0.5f, 0.5f, 0.5f); off_glVertex3f(0.5f, 0.5f, -0.5f); } } // Bottom Face if (y >= 0) { // if (y != Chunk.CHUNK_SIZE - 1 && (y == 0) || (!blocks[x][y - 1][z].isActive())) { off_glVertex3f(-0.5f, -0.5f, -0.5f); off_glVertex3f(0.5f, -0.5f, -0.5f); off_glVertex3f(0.5f, -0.5f, 0.5f); off_glVertex3f(-0.5f, -0.5f, 0.5f); } } // Right face if (x <= Chunk.CHUNK_SIZE - 1) { // if (x != 0 && (x == Chunk.CHUNK_SIZE - 1) || (!blocks[x + 1][y][z].isActive())) { off_glVertex3f(0.5f, -0.5f, -0.5f); off_glVertex3f(0.5f, 0.5f, -0.5f); off_glVertex3f(0.5f, 0.5f, 0.5f); off_glVertex3f(0.5f, -0.5f, 0.5f); } } // Left Face if (x >= 0) { // if (x != Chunk.CHUNK_SIZE - 1 && (x == 0) || (!blocks[x - 1][y][z].isActive())) { off_glVertex3f(-0.5f, -0.5f, -0.5f); off_glVertex3f(-0.5f, -0.5f, 0.5f); off_glVertex3f(-0.5f, 0.5f, 0.5f); off_glVertex3f(-0.5f, 0.5f, -0.5f); glColor3f(1, 1, 1); } } } // Draw a vertex with a offset. private void off_glVertex3f(float x, float y, float z) { glVertex3f(tx + x, ty + y, tz + z); } public void Update() { } public void render() { GL11.glCallList(chunkList); } public void remove() { GL11.glDeleteLists(chunkList, 1); chunkList = -1; } public int SetUpFlatGround() { Random rr = new Random(); for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = 0; y < CHUNK_SIZE; y++) { for (int z = 0; z < CHUNK_SIZE; z++) // set these blocks on { if (y == 0) blocks[x][y][z].setActive(true); else blocks[x][y][z].setActive(false); if(rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); else if(rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_DIRT); else blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_STONE); } } } return this.rebuildChunk(); } // Simple tree public void drawTree(int xpos, int ypos, int zpos, int height) { Random rr = new Random(); xpos = (int) Math.abs(rr.nextInt() % 10); zpos = (int) Math.abs(rr.nextInt() % 10); if (xpos == 0) xpos = 1; if (zpos <= 0) zpos = 1; if (height + 3 < Chunk.CHUNK_SIZE - this.maxHeight) { for (int y = this.maxHeight - 1; y < height + this.maxHeight - 1; y++) { blocks[xpos][ypos + y][zpos].setActive(true); blocks[xpos][ypos + y][zpos].setType(Block.BlockType.BLOCK_TYPE_TRUNK); } drawLeaf(xpos, ypos, zpos, this.maxHeight + height, Block.BlockType.BLOCK_TYPE_TREE_LEAF_ONE); } } public int drawLeaf(int xpos, int ypos, int zpos, int height, Block.BlockType type) { blocks[xpos][ypos + height - 2][zpos].setActive(true); blocks[xpos][ypos + height - 2][zpos].setType(type); blocks[xpos - 1][ypos + height - 3][zpos].setActive(true); blocks[xpos - 1][ypos + height - 3][zpos].setType(type); blocks[xpos + 1][ypos + height - 3][zpos].setActive(true); blocks[xpos + 1][ypos + height - 3][zpos].setType(type); blocks[xpos][ypos + height - 3][zpos + 1].setActive(true); blocks[xpos][ypos + height - 3][zpos + 1].setType(type); blocks[xpos][ypos + height - 3][zpos - 1].setActive(true); blocks[xpos][ypos + height - 3][zpos - 1].setType(type); return this.rebuildChunk(); } // Simple tree public void drawTree2(int xpos, int ypos, int zpos, int height, Block.BlockType type) { Random rr = new Random(); xpos = (int) Math.abs(rr.nextInt() % 8) + 2; zpos = (int) Math.abs(rr.nextInt() % 8) + 2; if (xpos == 0) xpos = 1; if (zpos <= 0) zpos = 1; if (height + 3 < Chunk.CHUNK_SIZE - this.maxHeight) { for (int y = this.maxHeight - 1; y < height + this.maxHeight - 1; y++) { blocks[xpos][ypos + y][zpos].setActive(true); blocks[xpos][ypos + y][zpos].setType(Block.BlockType.BLOCK_TYPE_TRUNK); } drawLeaf2(xpos, ypos, zpos, this.maxHeight + height, type); } } public int drawLeaf2(int xpos, int ypos, int zpos, int height, Block.BlockType type) { blocks[xpos][ypos + height - 1][zpos].setActive(true); blocks[xpos][ypos + height - 1][zpos].setType(type); blocks[xpos][ypos + height - 2][zpos].setActive(true); blocks[xpos][ypos + height - 2][zpos].setType(type); blocks[xpos][ypos + height - 3][zpos].setActive(true); blocks[xpos][ypos + height - 3][zpos].setType(type); blocks[xpos][ypos + height - 4][zpos].setActive(true); blocks[xpos][ypos + height - 4][zpos].setType(type); // Blocks[xpos][ypos + height-5][zpos].SetActive(true); // Blocks[xpos][ypos + height-5][zpos].SetType(type); blocks[xpos + 1][ypos + height - 2][zpos].setActive(true); blocks[xpos + 1][ypos + height - 2][zpos].setType(type); blocks[xpos - 1][ypos + height - 2][zpos].setActive(true); blocks[xpos - 1][ypos + height - 2][zpos].setType(type); blocks[xpos][ypos + height - 2][zpos - 1].setActive(true); blocks[xpos][ypos + height - 2][zpos - 1].setType(type); blocks[xpos][ypos + height - 2][zpos + 1].setActive(true); blocks[xpos][ypos + height - 2][zpos + 1].setType(type); blocks[xpos + 1][ypos + height - 3][zpos].setActive(true); blocks[xpos + 1][ypos + height - 3][zpos].setType(type); blocks[xpos - 1][ypos + height - 3][zpos].setActive(true); blocks[xpos - 1][ypos + height - 3][zpos].setType(type); blocks[xpos][ypos + height - 3][zpos - 1].setActive(true); blocks[xpos][ypos + height - 3][zpos - 1].setType(type); blocks[xpos][ypos + height - 3][zpos + 1].setActive(true); blocks[xpos][ypos + height - 3][zpos + 1].setType(type); blocks[xpos + 2][ypos + height - 3][zpos].setActive(true); blocks[xpos + 2][ypos + height - 3][zpos].setType(type); blocks[xpos + 1][ypos + height - 3][zpos + 1].setActive(true); blocks[xpos + 1][ypos + height - 3][zpos + 1].setType(type); blocks[xpos - 2][ypos + height - 3][zpos].setActive(true); blocks[xpos - 2][ypos + height - 3][zpos].setType(type); blocks[xpos - 1][ypos + height - 3][zpos - 1].setActive(true); blocks[xpos - 1][ypos + height - 3][zpos - 1].setType(type); blocks[xpos][ypos + height - 3][zpos + 2].setActive(true); blocks[xpos][ypos + height - 3][zpos + 2].setType(type); blocks[xpos + 1][ypos + height - 3][zpos - 1].setActive(true); blocks[xpos + 1][ypos + height - 3][zpos - 1].setType(type); blocks[xpos][ypos + height - 3][zpos - 2].setActive(true); blocks[xpos][ypos + height - 3][zpos - 2].setType(type); blocks[xpos - 1][ypos + height - 3][zpos + 1].setActive(true); blocks[xpos - 1][ypos + height - 3][zpos + 1].setType(type); return this.rebuildChunk(); } public int drawFoliage(int xpos, int zpos, Block.BlockType type) { blocks[xpos][this.maxHeight + 1][zpos].setActive(true); blocks[xpos][this.maxHeight + 1][zpos].setType(type); return this.rebuildChunk(); } public int drawRandomFoliage(Block.BlockType type) { Random rr = new Random(); int amountEnd = Math.abs(rr.nextInt() % 6); for (int amount = 0; amount < amountEnd; amount++) { int xpos = Math.abs(rr.nextInt() % 14); int zpos = Math.abs(rr.nextInt() % 14); blocks[xpos][this.maxHeight][zpos].setActive(true); blocks[xpos][this.maxHeight][zpos].setType(type); } return this.rebuildChunk(); } public int drawRandomBlock(Block.BlockType type, int randomMax) { Random rr = new Random(); int amountEnd = Math.abs(rr.nextInt() % randomMax); for (int amount = 0; amount < amountEnd; amount++) { int xpos = Math.abs(rr.nextInt() % 14); int zpos = Math.abs(rr.nextInt() % 14); blocks[xpos][this.maxHeight][zpos].setActive(true); blocks[xpos][this.maxHeight][zpos].setType(type); } return this.rebuildChunk(); } public int drawPole(int xpos, int zpos, int ypos, int height, Block.BlockType type) { for (int y = 0; y < height; y++) { blocks[xpos][ypos + y][zpos].setActive(true); blocks[xpos][ypos + y][zpos].setType(type); } return this.rebuildChunk(); } public int drawBlock(int xpos, int zpos, int ypos, Block.BlockType type) { blocks[xpos][ypos][zpos].setActive(true); blocks[xpos][ypos][zpos].setType(type); return this.rebuildChunk(); } public int SetupLandscape() { Random rr = new Random(); for (int x = 0; x < CHUNK_SIZE; x++) { for (int z = 0; z < CHUNK_SIZE; z++) { int height = (int) (SimplexNoise.noise(x / 16f, z / 16f) * 16f); if (height < 1) height = 1; for (int y = 0; y <= height; y++) // set these blocks on { blocks[x][y][z].setActive(true); if (rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); else blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_DIRT); } } } return this.rebuildChunk(); } public int RandomLandscape(boolean tree) { Random rr = new Random(); int height = -1; while (height < 0) height = (int) rr.nextInt() % 4; if (height >= this.maxHeight) this.maxHeight = height + 1; for (int x = 0; x < CHUNK_SIZE; x++) { for (int z = 0; z < CHUNK_SIZE; z++) { for (int y = 0; y <= height; y++) // set these blocks on { blocks[x][y][z].setActive(true); if (y == 0) { if (rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS2); else { if (rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); else blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS3); } // Blocks[x][y][z].SetType(BlockType.BlockType_Stone); } if (y == height && y != 0) { if (rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); else { if (rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS2); else blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS3); } } else if (y != 0) { blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_DIRT); } } } } if (tree && rr.nextBoolean()) { int treeHeight = CHUNK_SIZE - height; try { if (rr.nextBoolean()) this.drawTree(0, 1, 0, 6);// Math.abs(rr.nextInt() % // treeHeight)); else { if (rr.nextBoolean()) this.drawTree2(0, 1, 0, 6, Block.BlockType.BLOCK_TYPE_TREE_LEAF_TWO);// Math.abs(rr.nextInt() // % // treeHeight)); else this.drawTree2(0, 1, 0, height + 4, Block.BlockType.BLOCK_TYPE_TREE_LEAF_ONE);// Math.abs(rr.nextInt() // % // treeHeight)); } } catch (ArrayIndexOutOfBoundsException ex) { System.out.println("Tree too high"); } } return this.rebuildChunk(); } public int SetUpCube() { for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = 0; y < CHUNK_SIZE; y++) { for (int z = 0; z < CHUNK_SIZE; z++) // set these blocks on { blocks[x][y][z].setActive(true); blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); } } } return this.rebuildChunk(); } public int SetUpSpriral() { double angle = 0; float r = 10; float xrot = r * (float) Math.cos(angle); float zrot = r * (float) Math.cos(angle); for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = 0; y < CHUNK_SIZE; y++) { for (int z = 0; z < CHUNK_SIZE; z++) // set these blocks on { blocks[x][y][z].setActive(true); blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); } } } return this.rebuildChunk(); } public int SetUpDome() { for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = CHUNK_SIZE - 1; y > CHUNK_SIZE / 2; y--) { for (int z = 0; z < CHUNK_SIZE; z++) { blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_STONE); if (Math.sqrt((float) (x - CHUNK_SIZE / 2) * (x - CHUNK_SIZE / 2) + (y - CHUNK_SIZE / 2) * (y - CHUNK_SIZE / 2) + (z - CHUNK_SIZE / 2) * (z - CHUNK_SIZE / 2)) <= CHUNK_SIZE / 2) { blocks[x][y-8][z].setActive(true); blocks[x][y-8][z].setType(Block.BlockType.BLOCK_TYPE_GRASS3); } else { blocks[x][0][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); blocks[x][0][z].setActive(true); } } } } return this.rebuildChunk(); } public int SetUpSphere() { for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = 0; y < CHUNK_SIZE; y++) { for (int z = 0; z < CHUNK_SIZE; z++) { blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_STONE); if (Math.sqrt((float) (x - CHUNK_SIZE / 2) * (x - CHUNK_SIZE / 2) + (y - CHUNK_SIZE / 2) * (y - CHUNK_SIZE / 2) + (z - CHUNK_SIZE / 2) * (z - CHUNK_SIZE / 2)) <= CHUNK_SIZE / 2) { blocks[x][y][z].setActive(true); } else { blocks[x][y][z].setActive(false); } } } } return this.rebuildChunk(); } public int SetUpPyramid() { Random rr = new Random(); boolean b = rr.nextBoolean(); float xIndex = 0; float zIndex = 0; for (int y = 1; y < CHUNK_SIZE - 2; y++) { for (int z = (int) zIndex; z < CHUNK_SIZE - (int) zIndex; z++) { for (int x = (int) xIndex; x < CHUNK_SIZE - (int) xIndex; x++) { blocks[x][y][z].setActive(true); if (rr.nextBoolean()) blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS); else blocks[x][y][z].setType(Block.BlockType.BLOCK_TYPE_GRASS3); } } if (b) { xIndex += 0.5f; zIndex += 0.5f; } else { xIndex++; zIndex++; } } return this.rebuildChunk(); } public Chunk(int xOffset, int yOffset, int zOffset) { this.xOffset = xOffset; this.yOffset = yOffset; this.zOffset = zOffset; blocks = new Block[CHUNK_SIZE][CHUNK_SIZE][CHUNK_SIZE]; for (int x = 0; x < CHUNK_SIZE; x++) { for (int y = 0; y < CHUNK_SIZE; y++) { for (int z = 0; z < CHUNK_SIZE; z++) { blocks[x][y][z] = new Block(Block.BlockType.BLOCK_TYPE_DIRT); blocks[x][y][z].setActive(false); } } } } }