We committed all the stuff

Added compressed worldspaces,
Generation methods now generate chunks (Mandelbox and Menger Sponge)
Adding screenshot functionality
That's about it.
master
Colin 2014-09-12 17:07:15 -07:00
parent 3ce968075b
commit 2d52a11ace
86 changed files with 2024 additions and 531 deletions

BIN
VoxelEngine/bin/-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

BIN
VoxelEngine/bin/-405.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

BIN
VoxelEngine/bin/-508.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
VoxelEngine/bin/-550.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
VoxelEngine/bin/-701.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
VoxelEngine/bin/-718.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 492 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 397 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

BIN
VoxelEngine/bin/Thumbs.db Normal file

Binary file not shown.

BIN
VoxelEngine/src/1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

BIN
VoxelEngine/src/10.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

BIN
VoxelEngine/src/11.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 KiB

BIN
VoxelEngine/src/12.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 246 KiB

BIN
VoxelEngine/src/13.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 KiB

BIN
VoxelEngine/src/14.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
VoxelEngine/src/15.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 KiB

BIN
VoxelEngine/src/16.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 671 KiB

BIN
VoxelEngine/src/18.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

BIN
VoxelEngine/src/19.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

BIN
VoxelEngine/src/2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

BIN
VoxelEngine/src/20.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 KiB

BIN
VoxelEngine/src/21.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 KiB

BIN
VoxelEngine/src/22.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 654 KiB

BIN
VoxelEngine/src/23.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 KiB

BIN
VoxelEngine/src/24.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
VoxelEngine/src/25.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

BIN
VoxelEngine/src/26.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

BIN
VoxelEngine/src/27.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
VoxelEngine/src/28.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 KiB

BIN
VoxelEngine/src/29.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 KiB

BIN
VoxelEngine/src/3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 620 KiB

BIN
VoxelEngine/src/30.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 KiB

BIN
VoxelEngine/src/31.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

BIN
VoxelEngine/src/32.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 384 KiB

BIN
VoxelEngine/src/4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

BIN
VoxelEngine/src/5.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
VoxelEngine/src/6.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 KiB

BIN
VoxelEngine/src/7.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

BIN
VoxelEngine/src/8.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 792 KiB

BIN
VoxelEngine/src/9.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

BIN
VoxelEngine/src/Thumbs.db Normal file

Binary file not shown.

BIN
VoxelEngine/src/game.au Normal file

Binary file not shown.

BIN
VoxelEngine/src/menu.au Normal file

Binary file not shown.

View File

@ -0,0 +1,51 @@
package old;
import java.io.Serializable;
public class Chunk16 implements Serializable {
private static final long serialVersionUID = -4256447442964188571L;
private static int sz = 16;
private byte[][][] blocks = new byte[sz][sz][sz];
private int x, y, z = 0;
// methods
public void setBlock(byte type, int x, int y, int z) {
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
blocks[x][y][z] = type;
}
public byte getBlock(int x, int y, int z) {
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
return blocks[x][y][z];
else
return 0;
}
public boolean checkIfEmpty() {
for (int x = 0; x < sz; x++) {
for (int y = 0; y < sz; y++) {
for (int z = 0; z < sz; z++) {
if (blocks[x][y][z] != 0)
return false;
}
}
}
return true;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
}

View File

@ -0,0 +1,51 @@
package old;
import java.io.Serializable;
public class Chunk32 implements Serializable {
private static final long serialVersionUID = -4256447442964188571L;
private static int sz = 32;
private byte[][][] blocks = new byte[sz][sz][sz];
private int x, y, z = 0;
// methods
public void setBlock(byte type, int x, int y, int z) {
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
blocks[x][y][z] = type;
}
public byte getBlock(int x, int y, int z) {
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
return blocks[x][y][z];
else
return 0;
}
public boolean checkIfEmpty() {
for (int x = 0; x < sz; x++) {
for (int y = 0; y < sz; y++) {
for (int z = 0; z < sz; z++) {
if (blocks[x][y][z] != 0)
return false;
}
}
}
return true;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
}

View File

@ -0,0 +1,51 @@
package old;
import java.io.Serializable;
public class Chunk64 implements Serializable {
private static final long serialVersionUID = -4256447442964188571L;
private static int sz = 64;
private byte[][][] blocks = new byte[sz][sz][sz];
private int x, y, z = 0;
// methods
public void setBlock(byte type, int x, int y, int z) {
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
blocks[x][y][z] = type;
}
public byte getBlock(int x, int y, int z) {
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
return blocks[x][y][z];
else
return 0;
}
public boolean checkIfEmpty() {
for (int x = 0; x < sz; x++) {
for (int y = 0; y < sz; y++) {
for (int z = 0; z < sz; z++) {
if (blocks[x][y][z] != 0)
return false;
}
}
}
return true;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getZ() {
return z;
}
public void setZ(int z) {
this.z = z;
}
}

View File

@ -0,0 +1,34 @@
package old;
import voxelengine.BytePalette;
public class PaletteGenerator {
private static final int low = 1;
private static final int high = 32;
private static final int num = 10;
private static final int size = 32;
public static void main(String[] args) {
PaletteGenerator p = new PaletteGenerator();
}
public PaletteGenerator() {
for (int i = 0; i < num; i++) {
System.out.print("palettes.add(new BytePalette(\"r"+(i+1)+"\", new byte[] ");
generate();
System.out.print("));");
System.out.println();
}
}
private void generate() {
System.out.print("{ ");
for (int i = 0; i < size; i++) {
int r = (int) (Math.random() * high + low);
System.out.print(r);
if (i != size - 1)
System.out.print(", ");
}
System.out.print(" }");
}
}

View File

@ -0,0 +1,207 @@
package old;
public class TestArray {
private int size = 100;
private int[][][] array = new int[size][size][size];
public TestArray() {
long time = System.nanoTime();
initializeArray();
System.out.println("Initialization: "+(System.nanoTime() - time)/1000);
if (size <= 5) printArray();
time = System.nanoTime();
shiftArray(1, 0, 0);
System.out.println("Move with fors: "+(System.nanoTime() - time)/1000);
if (size <= 5) printArray();
initializeArray();
if (size <= 5) printArray();
time = System.nanoTime();
shiftArraySys(1, 0, 0);
System.out.println("Move with sys: "+(System.nanoTime() - time)/1000);
if (size <= 5) printArray();
}
public static void main(String[] args) {
@SuppressWarnings("unused")
TestArray t = new TestArray();
}
private void initializeArray() {
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++) {
array[x][y][z] = x + y + z;
}
}
private void shiftArraySys(int xshift, int yshift, int zshift) {
int[][][] newarray = array.clone();
// xshift
if (xshift > 0) {
System.arraycopy(newarray, 0, array, xshift, array.length - xshift);
} else if (xshift < 0) {
System.arraycopy(newarray, xshift, array, 0, array.length + xshift);
}
// yshift
if (yshift > 0) {
for (int x = 0; x < size; x++) {
System.arraycopy(newarray[x], 0, array[x], yshift, array[x].length - yshift);
}
} else if (yshift < 0) {
for (int x = 0; x < size; x++) {
System.arraycopy(newarray[x], yshift, array[x], 0, array[x].length + yshift);
}
}
// zshift
if (zshift > 0) {
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
System.arraycopy(newarray[x][y], 0, array[x][y], zshift, array[x][y].length - zshift);
}
}
} else if (yshift < 0) {
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
System.arraycopy(newarray[x][y], zshift, array[x][y], 0, array[x][y].length + zshift);
}
}
}
}
private void zeroArraySys(int xshift, int yshift, int zshift) {
if (xshift > 0) {
for (int x = 0; x < xshift; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++) {
System.out.println("Zeroing "+x+","+y+","+z);
array[x][y][z] = 0;
}
} else if (xshift < 0) {
for (int x = size - 1; x >= size - xshift; x--)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++) {
array[x][y][z] = 0;
}
}
if (yshift > 0) {
for (int y = 0; y < yshift; y++)
for (int x = 0; x < size; x++)
for (int z = 0; z < size; z++) {
array[x][y][z] = 0;
}
} else if (yshift < 0) {
for (int y = size - 1; y >= size - yshift; y--)
for (int x = 0; x < size; x++)
for (int z = 0; z < size; z++) {
array[x][y][z] = 0;
}
}
if (zshift > 0) {
for (int z = 0; z < zshift; z++)
for (int y = 0; y < size; y++)
for (int x = 0; x < size; x++) {
array[x][y][z] = 0;
}
} else if (zshift < 0) {
for (int z = size - 1; z >= size - zshift; z--)
for (int y = 0; y < size; y++)
for (int x = 0; x < size; x++) {
array[x][y][z] = 0;
}
}
}
private void shiftArray(int xshift, int yshift, int zshift) {
// xshift
if (xshift > 0) {
// positive shift on x
for (int x = size - 1; x >= 0; x--)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++) {
if (x < xshift)
array[x][y][z] = 0;
else
array[x][y][z] = array[x - xshift][y][z];
}
} else if (xshift < 0) {
// negative shift on x
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++) {
if (x >= size + xshift)
array[x][y][z] = 0;
else
array[x][y][z] = array[x - xshift][y][z];
}
}
// yshift
if (yshift > 0) {
// positive shift on y
for (int y = size - 1; y >= 0; y--)
for (int x = 0; x < size; x++)
for (int z = 0; z < size; z++) {
if (y < yshift)
array[x][y][z] = 0;
else
array[x][y][z] = array[x][y - yshift][z];
}
} else if (yshift < 0) {
// negative shift on y
for (int y = 0; y < size; y++)
for (int x = 0; x < size; x++)
for (int z = 0; z < size; z++) {
if (y >= size + yshift)
array[x][y][z] = 0;
else
array[x][y][z] = array[x][y - yshift][z];
}
}
// zshift
if (zshift > 0) {
// positive shift on z
for (int z = size - 1; z >= 0; z--)
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++) {
if (z < zshift)
array[x][y][z] = 0;
else
array[x][y][z] = array[x][y][z - zshift];
}
} else if (zshift < 0) {
// negative shift on z
for (int z = 0; z < size; z++)
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++) {
if (z >= size + zshift)
array[x][y][z] = 0;
else
array[x][y][z] = array[x][y][z - zshift];
}
}
}
private void printArray() {
for (int x = 0; x < size; x++) {
System.out.println("Plane ["+x+"]");
for (int y = 0; y < size; y++) {
for (int z = 0; z < size; z++) {
System.out.print(array[x][y][z]+",");
}
System.out.println();
}
}
System.out.println();
System.out.println();
}
}

View File

@ -0,0 +1,111 @@
package old;
import java.util.ArrayList;
public class TestArrayList {
private int size = 100;
private ArrayList<ArrayList<ArrayList<Integer>>> array = new ArrayList<ArrayList<ArrayList<Integer>>>(size);
public static void main(String[] args) {
TestArrayList t = new TestArrayList();
}
public TestArrayList() {
Long time = System.nanoTime();
initializeArray();
System.out.println("Initialization: "+(System.nanoTime() - time)/1000);
if (size <= 5) printArray();
time = System.nanoTime();
shiftArray(0, 0, 1);
System.out.println("Move with fors: "+(System.nanoTime() - time)/1000);
if (size <= 5) printArray();
}
private void shiftArray(int xshift, int yshift, int zshift) {
if (xshift > 0 ) {
for (int x = 0; x < xshift; x++) {
array.remove(size - 1);
array.add(0, new ArrayList<ArrayList<Integer>>(size));
for (int y = 0; y < size; y++) {
array.get(x).add(new ArrayList<Integer>(size));
for (int z = 0; z < size; z++) {
array.get(x).get(y).add(0);
}
}
}
} else if (xshift < 0) {
for (int x = 0; x < xshift; x++) {
array.remove(0);
array.add(new ArrayList<ArrayList<Integer>>(size));
for (int y = 0; y < size; y++) {
array.get(size - 1).add(new ArrayList<Integer>(size));
for (int z = 0; z < size; z++) {
array.get(x).get(y).add(0);
}
}
}
}
if (yshift > 0) {
for (int x = 0; x < size; x++)
for (int y = 0; y < yshift; y++) {
array.get(x).remove(size - 1);
array.get(x).add(0, new ArrayList<Integer>(size));
for (int z = 0; z < size; z++) {
array.get(x).get(y).add(0);
}
}
} else if (yshift < 0) {
for (int x = 0; x < size; x++)
for (int y = 0; y < yshift; y++) {
array.get(x).remove(0);
array.get(x).add(new ArrayList<Integer>(size));
for (int z = 0; z < size; z++) {
array.get(x).get(size - 1).add(0);
}
}
}
if (zshift > 0) {
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < zshift; z++) {
array.get(x).get(y).remove(size - 1);
array.get(x).get(y).add(0, 0);
}
} else if (zshift < 0) {
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < zshift; z++) {
array.get(x).get(y).remove(0);
array.get(x).get(y).add(0);
}
}
}
private void printArray() {
for (int x = 0; x < size; x++) {
System.out.println("Plane ["+x+"]");
for (int y = 0; y < size; y++) {
for (int z = 0; z < size; z++) {
System.out.print(array.get(x).get(y).get(z)+",");
}
System.out.println();
}
}
System.out.println();
System.out.println();
}
private void initializeArray() {
for (int x = 0; x < size; x++) {
array.add(new ArrayList<ArrayList<Integer>>(size));
for (int y = 0; y < size; y++) {
array.get(x).add(new ArrayList<Integer>(size));
for (int z = 0; z < size; z++) {
array.get(x).get(y).add(x + y + z);
}
}
}
}
}

View File

@ -0,0 +1,64 @@
package old;
import java.applet.Applet;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Label;
import java.awt.Panel;
import voxelengine.World;
public class WorldTester extends Applet {
private static final long serialVersionUID = 1L;
private static final int worldSize = 20;
private static final int fractalSize = worldSize * 14;
private static final byte num = 56;
private static final int pnlSize = 100;
public void init() {
// creating world
System.out.println("Creating world size: "+worldSize);
Long time = System.currentTimeMillis();
World world = new World(worldSize);
time = (System.currentTimeMillis() - time);
System.out.println("Time: "+time+"ms \n");
// initializing world data
world.addColorBlockTypes();
world.addPalettes();
displayColors(world);
// generating mandelbox
// System.out.println("Generating mandelbox...");
// int offset = (worldSize * 16 - fractalSize)/2;
// time = System.currentTimeMillis();
// world.getGenerator().generateMandelbox("test", fractalSize, 2, 5, 4, 12, 4, offset, offset, offset);
// time = (System.currentTimeMillis() - time);
// System.out.println("Time: "+time+"ms \n");
// saving world
// System.out.println("Saving world...");
// time = System.currentTimeMillis();
// world.save("test.wrl");
// time = (System.currentTimeMillis() - time);
// System.out.println("Time: "+time+"ms \n");
}
private void displayColors(World world) {
this.setSize(600, 800);
for (byte i = 1; i <= num; i++) {
Panel pnl = new Panel();
pnl.setPreferredSize(new Dimension(pnlSize + 8, pnlSize + 32));
Panel col = new Panel();
col.setPreferredSize(new Dimension(pnlSize, pnlSize));
col.setBackground(world.getType(i).getColor());
pnl.add(col);
Label lb = new Label();
lb.setText(world.getType(i).getName() + " " + Integer.toString(i));
pnl.add(lb);
add(pnl);
}
}
}

View File

@ -20,6 +20,19 @@ public class BytePalette {
}
public void printContents() {
for (int i = 0; i < palette.length; i++)
System.out.println(get(i));
System.out.print(get(i)+",");
System.out.println();
}
public BytePalette remap(int size) {
byte[] a = new byte[size];
for (int i = 0; i < size; i++) {
int n = (getSize() - 1) * (i+1)/size;
a[i] = palette[n];
}
BytePalette p = new BytePalette(name+"-remapped", a);
return p;
}
public int getSize() {
return palette.length;
}
}

View File

@ -1,15 +1,32 @@
package voxelengine;
public class Chunk {
private static int sz = 16;
private byte[][][] blocks = new byte[sz][sz][sz];
import java.io.Serializable;
public class Chunk implements Serializable {
private static final long serialVersionUID = -4256447442964188571L;
private int sz;
private byte[][][] blocks;
// constructor
public Chunk(int sz) {
this.sz = sz;
this.blocks = new byte[sz][sz][sz];
}
public Chunk(int sz, byte[][][] blocks) {
this.sz = sz;
this.blocks = blocks;
}
// methods
public void setBlock(byte type, int x, int y, int z) {
blocks[x][y][z] = type;
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
blocks[x][y][z] = type;
}
public byte getBlock(int x, int y, int z) {
return blocks[x][y][z];
if ((x >= 0) && (y >= 0) && (z >= 0) && (x < sz) && (y < sz) && (z < sz))
return blocks[x][y][z];
else
return 0;
}
public boolean checkIfEmpty() {
for (int x = 0; x < sz; x++) {
@ -22,4 +39,10 @@ public class Chunk {
}
return true;
}
public Chunk clone() {
return new Chunk(this.sz, this.blocks);
}
public int getSize() {
return sz;
}
}

View File

@ -17,6 +17,8 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.File;
import java.nio.file.Files;
import javax.swing.Box;
import javax.swing.BoxLayout;
@ -30,7 +32,6 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
private Label sizeL, colorL, worldSizeL, minItL, maxItL, powerL, zoomL, resL, pixL, castL, cutoffL;
private Choice choice, color;
private AudioClip sound;
private Image bg1, bg2, bg3, bg4, bg5, bg6, bg7, bg8, bg9, bg10;
private Image[] slideshow;
private Panel pnl;
private int ndx = 0;
@ -128,7 +129,7 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
worldSizeL.setForeground(Color.LIGHT_GRAY);
worldSizeL.setBackground(Color.BLACK);
worldSizeL.setMaximumSize(new Dimension(70, 20));
worldSize = new TextField("20");
worldSize = new TextField("6");
worldSize.setMaximumSize(new Dimension(50, 20));
choice = new Choice();
choice.addItem("Menger Sponge");
@ -171,7 +172,7 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
colorL.setBackground(Color.BLACK);
colorL.setPreferredSize(new Dimension(50, 20));
color = new Choice();
color.setPreferredSize(new Dimension(80, 20));
color.setPreferredSize(new Dimension(120, 20));
sizeL = new Label("Size: ");
sizeL.setForeground(Color.LIGHT_GRAY);
sizeL.setBackground(Color.BLACK);
@ -195,7 +196,7 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
powerL.setBackground(Color.BLACK);
powerL.setPreferredSize(new Dimension(50, 20));
power = new TextField("8");
power.setPreferredSize(new Dimension(50, 20));
power.setPreferredSize(new Dimension(100, 20));
zoomL = new Label("Zoom: ");
zoomL.setForeground(Color.LIGHT_GRAY);
zoomL.setBackground(Color.BLACK);
@ -216,10 +217,9 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
pnl.add(Box.createRigidArea(new Dimension(10,0)));
pnl.add(sizeL, BorderLayout.CENTER);
pnl.add(size, BorderLayout.CENTER);
pnl.add(Box.createRigidArea(new Dimension(50,0)));
pnl.add(powerL, BorderLayout.CENTER);
pnl.add(power, BorderLayout.CENTER);
pnl.add(Box.createRigidArea(new Dimension(50,0)));
pnl.add(Box.createRigidArea(new Dimension(40,0)));
pnl.add(zoomL, BorderLayout.CENTER);
pnl.add(zoom, BorderLayout.CENTER);
pnl.add(minItL, BorderLayout.CENTER);
@ -235,22 +235,7 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
}
public void mengerMenu() {
color.setEnabled(true);
colorL.setEnabled(true);
colorL.setText("Color: ");
color.removeAll();
color.addItem("red");
color.addItem("green");
color.addItem("blue");
color.addItem("yellow");
color.addItem("orange");
color.addItem("magenta");
color.addItem("pink");
color.addItem("cyan");
color.addItem("black");
color.addItem("white");
color.addItem("gray");
color.addItem("darkGray");
addColors();
size.setText("81");
power.setEnabled(false);
zoom.setEnabled(false);
@ -258,24 +243,9 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
maxIt.setEnabled(false);
cutoff.setEnabled(false);
}
public void crossMenu() {
color.setEnabled(true);
colorL.setEnabled(true);
colorL.setText("Color: ");
color.removeAll();
color.addItem("red");
color.addItem("green");
color.addItem("blue");
color.addItem("yellow");
color.addItem("orange");
color.addItem("magenta");
color.addItem("pink");
color.addItem("cyan");
color.addItem("black");
color.addItem("white");
color.addItem("gray");
color.addItem("darkGray");
addColors();
powerL.setText("Scale: ");
power.setText("3");
size.setText("63");
@ -287,22 +257,7 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
}
public void octahedronMenu() {
color.setEnabled(true);
colorL.setEnabled(true);
colorL.setText("Color: ");
color.removeAll();
color.addItem("red");
color.addItem("green");
color.addItem("blue");
color.addItem("yellow");
color.addItem("orange");
color.addItem("magenta");
color.addItem("pink");
color.addItem("cyan");
color.addItem("black");
color.addItem("white");
color.addItem("gray");
color.addItem("darkGray");
addColors();
powerL.setText("Scale: ");
power.setText("7");
size.setText("63");
@ -314,16 +269,7 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
}
public void bulbMenu() {
color.setEnabled(true);
colorL.setEnabled(true);
colorL.setText("Palette: ");
color.removeAll();
color.addItem("test");
color.addItem("blackNblue");
color.addItem("glory");
color.addItem("boutique");
color.addItem("goldfish");
color.addItem("dreamy");
addPalettes();
powerL.setText("Power: ");
size.setText("81");
power.setEnabled(true);
@ -336,16 +282,7 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
}
public void boxMenu() {
color.setEnabled(true);
colorL.setEnabled(true);
colorL.setText("Palette: ");
color.removeAll();
color.addItem("test");
color.addItem("blackNblue");
color.addItem("glory");
color.addItem("boutique");
color.addItem("goldfish");
color.addItem("dreamy");
addPalettes();
powerL.setText("Scale: ");
size.setText("81");
power.setText("1.5");
@ -357,11 +294,57 @@ public class Menu extends Applet implements ActionListener, ItemListener, Runnab
cutoff.setText("5");
}
private void addPalettes() {
color.setEnabled(true);
colorL.setText("Palette: ");
color.removeAll();
color.addItem("test");
color.addItem("Glory");
color.addItem("Boutique");
color.addItem("Goldfish");
color.addItem("Dreamy");
color.addItem("Technological");
color.addItem("Murderous");
color.addItem("Golddigger");
color.addItem("Undergrowth");
color.addItem("Feeling Blue");
color.addItem("Oranje");
color.addItem("Tropical Sea");
color.addItem("Motherboard");
color.addItem("Fire in the Night");
color.addItem("Sulfur");
color.addItem("Alien");
color.addItem("Fruit Shake");
color.addItem("Frosted Cactus");
color.addItem("Borg");
}
private void addColors() {
color.setEnabled(true);
colorL.setText("Color: ");
color.removeAll();
color.addItem("red");
color.addItem("green");
color.addItem("blue");
color.addItem("yellow");
color.addItem("orange");
color.addItem("magenta");
color.addItem("pink");
color.addItem("cyan");
color.addItem("black");
color.addItem("white");
color.addItem("gray");
color.addItem("darkGray");
}
public void loadMenu() {
color.setEnabled(true);
power.setEnabled(false);
color.removeAll();
color.addItem("test.wrl");
color.addItem("10-Mandelbulb-Fire in the Night-256.wrl");
color.addItem("37-Menger Sponge-red-2187.wrl");
color.addItem("35-Mandelbox-Borg-2000.wrl");
zoom.setEnabled(false);
minIt.setEnabled(false);
maxIt.setEnabled(false);

View File

@ -0,0 +1,833 @@
package voxelengine;
import static java.lang.Math.*;
import java.text.DecimalFormat;
public class ObjectGenerator {
private int csz;
private int recursionCounter = 0;
private int recursionGoal = 0;
private long messageDelay = 500;
private long time = 0;
private World world;
public ObjectGenerator(World world, int chunkSize) {
this.world = world;
this.csz = chunkSize;
}
public int getCounter() {
return recursionCounter;
}
/***************************************************************
********************* Basic Shape Methods *********************
***************************************************************/
public void generateCube(byte id, int d0, int xo, int yo, int zo) {
Chunk c = new Chunk(csz);
for (int x = xo; (x < csz) && (x < xo + d0); x++) {
for (int y = yo; (y < csz) && (y < yo + d0); y++) {
for (int z = zo; (z < csz) && (z < zo + d0); z++) {
c.setBlock(id, x, y, z);
}
}
}
world.setChunk(1, 1, 1, c);
}
public void generateBox(byte id, int d0, int xOffset, int yOffset, int zOffset) {
for (int x = 0; x < d0; x++) {
for (int y = 0; y < d0; y++) {
world.setBlock(id, x + xOffset, y + yOffset, zOffset);
world.setBlock(id, x + xOffset, y + yOffset, (d0 - 1) + zOffset);
}
}
for (int y = 0; y < d0; y++) {
for (int z = 0; z < d0; z++) {
world.setBlock(id, xOffset, y + yOffset, z + zOffset);
world.setBlock(id, (d0 - 1) + xOffset, y + yOffset, z + zOffset);
}
}
for (int x = 0; x < d0; x++) {
for (int z = 0; z < d0; z++) {
world.setBlock(id, x + xOffset, yOffset, z + zOffset);
world.setBlock(id, x + xOffset, (d0 - 1) + yOffset, z + zOffset);
}
}
}
/***************************************************************
******************** Menger Sponge Methods ********************
***************************************************************/
public void generateMengerSponge(byte id, int d0, int xOffset, int yOffset, int zOffset) {
// set recursion goal
if (recursionGoal == 0) {
recursionGoal = getMengerGoal(d0);
// System.out.println("Menger sponge goal: "+recursionGoal);
time = System.currentTimeMillis();
}
// increment recursion counter
recursionCounter++;
// print recursion message once every messageDelay seconds
if (System.currentTimeMillis() - time > messageDelay) {
double recursionProgress = (double) 100 * (recursionCounter) / (recursionGoal);
DecimalFormat df = new DecimalFormat("#.##");
System.out.println(df.format(recursionProgress) + "%");
time = System.currentTimeMillis();
}
// place block and return if dimension = 1
if (d0 == 1) {
world.setBlock(id, xOffset, yOffset, zOffset);
return;
}
// 1/3 of dimension
int d1 = d0 / 3;
// recursion loop
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
if ((y == 1) && (x == 1))
continue;
for (int z = 0; z < 3; z++) {
if (((y == 1) && (z == 1)) || ((x == 1) && (z == 1)))
continue;
// recursion
if (d0 > 3)
generateMengerSponge(id, d1, x * d1 + xOffset, y * d1 + yOffset, z * d1 + zOffset);
else {
world.setBlock(id, x + xOffset, y + yOffset, z + zOffset);
}
}
}
}
}
private int getMengerGoal(int d0) {
int volume = 0;
int it = 0;
while (d0 >= 3) {
d0 /= 3;
it++;
}
while (it >= 0) {
it--;
volume += pow(20, it);
}
return volume;
}
// menger sponge chunk-based generation
public void generateMengerChunks(byte id, int d, int x1, int y1, int z1) {
// calculate the coordinates for the starting chunks
int xs = x1 / csz;
int ys = y1 / csz;
int zs = z1 / csz;
// calculate the coordinates for the ending chunks
int xe = (x1 + d) / csz;
int ye = (y1 + d) / csz;
int ze = (z1 + d) / csz;
// generate each chunk and set it in the world
Long time = System.currentTimeMillis();
DecimalFormat df = new DecimalFormat("#.##");
int totalChunks = (xe - xs + 1)*(ye - ys + 1)*(ze - zs + 1);
for (int x = xs; x <= xe; x++)
for (int y = ys; y <= ye; y++)
for (int z = zs; z <= ze; z++) {
world.setChunk(x, y, z, generateMengerChunk(id, d, x1, y1, z1, x - xs, y - ys, z - zs));
if ((System.currentTimeMillis() - time) > messageDelay) {
int currentChunks = (ze - zs + 1)*(ye - ys + 1)*(x - xs) + (ze - zs + 1)*(y - ys) + (z - zs);
double progress = (double) 100 * currentChunks/totalChunks;
System.out.println(df.format(progress)+"%");
time = System.currentTimeMillis();
}
}
}
public Chunk generateFilledChunk(byte id) {
Chunk c = new Chunk(csz);
for (int x = 0; x < csz; x++)
for (int y = 0; y < csz; y++)
for (int z = 0; z < csz; z++) {
c.setBlock(id, x, y, z);
}
return c;
}
// generate a single chunk that's part of a larger Menger Sponge
public Chunk generateMengerChunk(byte id, int d, int x1, int y1, int z1, int xc, int yc, int zc) {
// prepare the chunk and the BlockType
Chunk c = new Chunk(csz);
// here we calculate the upper limit in each Cartesian direction of the object
// that we're generating. this is important for us to not attempt to generate
// blocks outside of the object's actual dimensions
int x2 = x1 + d;
int y2 = y1 + d;
int z2 = z1 + d;
// we loop over the entire chunk, calculating Cartesian values relative to the
// origin of the fractal we're generating. we also calculate the real Cartesian
// values for each point to make sure we're in the range of the fractal we're
// generating.
for (int x = 0; x < csz; x++) {
int xRelative = xc * csz + x - (x1 % csz);
int xReal = xRelative + x1;
if ((xReal < x1) || (xReal > x2))
continue;
for (int y = 0; y < csz; y++) {
int yRelative = yc * csz + y - (y1 % csz);
int yReal = yRelative + y1;
if ((yReal < y1) || (yReal > y2))
continue;
for (int z = 0; z < csz; z++) {
int zRelative = zc * csz + z - (z1 % csz);
int zReal = zRelative + z1;
if ((zReal < z1) || (zReal > z2))
continue;
// if the location is part of the Menger Sponge set, we place a block
if (mengerTest(d, xRelative, yRelative, zRelative)) {
// System.out.println("Set block at (" + xRelative + ", " + yRelative + ", " + zRelative + ")");
c.setBlock(id, x, y, z);
}
}
}
}
return c;
}
// recursively test if a location in Cartesian coordinates is a part of the
// Menger Sponge set
public boolean mengerTest(int d, int x, int y, int z) {
int d3 = d / 3;
// test if x, y, or z is in the d/3 to 2d/3 range
boolean xOut = ((x >= d3) && (x < 2 * d3));
boolean yOut = ((y >= d3) && (y < 2 * d3));
boolean zOut = ((z >= d3) && (z < 2 * d3));
// if two Cartesian values are out of range, return false
// else, if d >= 9 recurse with d/3 and modulused Cartesian values
// else, return true
if ((xOut && yOut) || (yOut && zOut) || (xOut && zOut)) {
return false;
} else if (d >= 9) {
return mengerTest(d3, x % d3, y % d3, z % d3);
} else {
return true;
}
}
// public void generateMengerSpongeChunks(byte id, int d0, int xo, int yo, int zo) {
// int xlim = (xo + d0) / csz;
// int ylim = (yo + d0) / csz;
// int zlim = (zo + d0) / csz;
// int xs = xo / csz;
// int ys = yo / csz;
// int zs = zo / csz;
// int xm = d0;
// int ym = d0;
// int zm = d0;
//
// int ixo = xo % csz;
// for (int i = xs; i <= xlim; i++) {
// int iyo = yo % csz;
// ym = d0;
// zm = d0;
// for (int j = ys; j <= ylim; j++) {
// int izo = zo % csz;
// zm = d0;
// for (int k = zs; k <= zlim; k++) {
// Chunk c = generateMengerChunk(id, d0, ixo, iyo, izo, (i - xs) * csz, (j - ys) * csz,
// (k - zs) * csz, xm, ym, zm);
// world.setChunk(i, j, k, c);
// izo = 0;
// zm -= (csz - izo);
// }
// ym -= (csz - iyo);
// iyo = 0;
// }
// xm -= (csz - ixo);
// ixo = 0;
// }
// }
//
// public Chunk generateMengerChunk(byte id, int d0, int xo, int yo, int zo, int cxo, int cyo, int czo, int xm,
// int ym, int zm) {
// Chunk c = new Chunk(csz);
// for (int x = 0; (x < 64 - xo) && (x < xm); x++)
// for (int y = 0; (y < 64 - yo) && (y < ym); y++)
// for (int z = 0; (z < 64 - zo) && (z < zm); z++) {
// boolean b = mengerTest(d0, x + cxo, y + cyo, z + czo);
// if (b)
// c.setBlock(id, x + xo, y + yo, z + zo);
// }
//
// return c;
// }
//
// public boolean mengerTest(int d0, int x, int y, int z) {
// boolean bx = ((x >= d0 / 3) && (x < 2 * d0 / 3));
// boolean by = ((y >= d0 / 3) && (y < 2 * d0 / 3));
// boolean bz = ((z >= d0 / 3) && (z < 2 * d0 / 3));
//
// // recursion
// if (d0 > 3) {
// int d1 = d0 / 3;
// if ((bx) && (by || bz))
// return mengerTest(d1, x % d1, y % d1, z % d1);
// else if (by && bz)
// return mengerTest(d1, x % d1, y % d1, z % d1);
//
// return false;
// }
//
// if ((bx) && (by || bz))
// return true;
// else if (by && bz)
// return true;
//
// return false;
// }
/***************************************************************
********************* Mandelbulb Methods *********************
***************************************************************/
// generate mandelbulb
public void generateMandelbulb(String name, int d, double power, double cutoff, int xOffset, int yOffset, int zOffset, int itMin, int itMax) {
// prepare palette
BytePalette palette = world.getPalette(name);
if (itMax - itMin > palette.getSize()) {
System.out.println("Remapping palette from " + palette.getSize() + " to " + (itMax - itMin));
palette = palette.remap(itMax - itMin);
}
// iterate for all x,y,z
for (int x = 0; x < d; x++) {
double xc = tf(x, d);
for (int y = 0; y < d; y++) {
// print message once every messageDelay seconds
if (System.currentTimeMillis() - time > messageDelay) {
double progress = (double) 100 * (d * d * x) / (pow(d, 3));
DecimalFormat df = new DecimalFormat("#.##");
System.out.println(df.format(progress) + "%");
time = System.currentTimeMillis();
}
double yc = tf(y, d);
for (int z = 0; z < d; z++) {
double zc = tf(z, d);
int iterations = -1;
double[] C = new double[] { xc, yc, zc };
double[] Z = new double[] { 0, 0, 0 };
// iterate over vectors
while ((mag(Z) <= cutoff) && (iterations < itMax)) {
Z = add(formula(Z, power), C);
iterations++;
}
// place block if cutoff reached in itMin -> itMax range
if ((iterations >= itMin) && (iterations < itMax)) {
byte id = palette.get(iterations - itMin);
// System.out.println("Placing block "+id+" at ("+(xOffset + x)+","+(yOffset + y)+","+(zOffset + z)+")");
world.setBlock(id, xOffset + x, yOffset + y, zOffset + z);
}
}
}
}
}
public void generateMandelbulbChunks(String name, int d, double power, double cutoff, int itMin, int itMax, int xo, int yo, int zo) {
int xlim = (xo + d) / csz;
int ylim = (yo + d) / csz;
int zlim = (zo + d) / csz;
int xs = xo / csz;
int ys = yo / csz;
int zs = zo / csz;
int xm = d;
int ym = d;
int zm = d;
int ixo = xo % csz;
for (int i = xs; i <= xlim; i++) {
int iyo = yo % csz;
ym = d;
zm = d;
for (int j = ys; j <= ylim; j++) {
int izo = zo % csz;
zm = d;
for (int k = zs; k <= zlim; k++) {
Chunk c = generateMandelbulbChunk(name, d, power, cutoff, itMin, itMax, ixo, iyo, izo, (i - xs) * csz, (j - ys) * csz, (k - zs) * csz, xm, ym, zm);
world.setChunk(i, j, k, c);
zm -= csz - izo;
izo = 0;
}
ym -= csz - iyo;
iyo = 0;
}
xm -= csz - ixo;
ixo = 0;
}
}
public Chunk generateMandelbulbChunk(String name, int d, double power, double cutoff, int itMin, int itMax, int xo, int yo, int zo, int cxo, int cyo, int czo, int xm, int ym, int zm) {
Chunk chunk = new Chunk(64);
BytePalette palette = world.getPalette(name);
for (int x = 0; (x < 64 - xo) && (x < xm); x++) {
double xc = (2.0 * (x + cxo)) / (d - 1) - 1.0;
// double xc = tf(x + cxo, d);
for (int y = 0; (y < 64 - yo) && (y < ym); y++) {
double yc = (2.0 * (y + cyo)) / (d - 1) - 1.0;
for (int z = 0; (z < 64 - zo) && (z < zm); z++) {
double zc = (2.0 * (z + czo)) / (d - 1) - 1.0;
int iterations = -1;
double[] C = new double[] { xc, yc, zc };
double[] Z = new double[] { 0, 0, 0 };
// iterate over vectors
while ((mag(Z) <= cutoff) && (iterations < itMax)) {
Z = add(formula(Z, power), C);
iterations++;
}
// place block if cutoff reached in itMin -> itMax range
if ((iterations >= itMin) && (iterations < itMax)) {
byte id = palette.get(iterations - itMin);
chunk.setBlock(id, xo + x, yo + y, zo + z);
}
}
}
}
return chunk;
}
private double tf(int v, int d) {
return (2.0 * v) / ((double) d) - 1.0;
}
private double mag(double[] vec) {
return sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
}
private double[] add(double[] vec1, double[] vec2) {
return new double[] { vec1[0] + vec2[0], vec1[1] + vec2[1], vec1[2] + vec2[2] };
}
// mandelbulb vector growth formula
// if current vector magnitude > 1 and t is not too close to a multiple of (pi/2)
// this will give a vector of greater magnitude than the vector put in
// n is the rate at which vector magnitude grows.
private double[] formula(double[] vec, double n) {
double t = theta(vec);
double p = phi(vec);
double k = pow(mag(vec), n);
return new double[] { k * sin(n * t) * cos(n * p), k * sin(n * t) * sin(n * p), k * cos(n * t) };
}
// theta vector value (arccos)
private double theta(double[] vec) {
return (acos(vec[2] / (mag(vec) + 0.000000001)));
}
// phi vector value (arctan)
private double phi(double[] vec) {
return (atan(vec[1] / (vec[0] + 0.000000001)));
}
/***************************************************************
********************** Mandelbox Methods **********************
***************************************************************/
// generate mandelbox
public void generateMandelbox(String name, int d, double scale, double cutoff, int itMin, int itMax, double tfmult,
int xOffset, int yOffset, int zOffset) {
// prepare palette
BytePalette palette = world.getPalette(name);
if (itMax - itMin > palette.getSize()) {
System.out.println("Remapping palette from " + palette.getSize() + " to " + (itMax - itMin));
palette = palette.remap(itMax - itMin);
}
// iterate for all x,y,z
double tfsub = tfmult / 2;
for (int x = 0; x < d; x++) {
double xc = (tfmult * x) / (d - 1) - tfsub;
for (int y = 0; y < d; y++) {
// print message once every messageDelay seconds
if (System.currentTimeMillis() - time > messageDelay) {
double progress = (double) 100 * (d * d * x) / (pow(d, 3));
DecimalFormat df = new DecimalFormat("#.##");
System.out.println(df.format(progress) + "%");
time = System.currentTimeMillis();
}
double yc = (tfmult * y) / (d - 1) - tfsub;
for (int z = 0; z < d; z++) {
double zc = (tfmult * z) / (d - 1) - tfsub;
int iterations = -1;
double[] C = new double[] { xc, yc, zc };
double[] Z = new double[] { 0, 0, 0 };
while ((mag(Z) < cutoff) && (iterations < itMax)) {
Z = add(mult(scale, boxformula(Z)), C);
iterations++;
}
if ((iterations >= itMin) && (iterations < itMax)) {
// place block if cutoff reached in itMin -> itMax range
if ((iterations >= itMin) && (iterations < itMax)) {
byte id = palette.get(iterations - itMin);
// System.out.println("Placing block "+id+" at ("+(xOffset + x)+","+(yOffset + y)+","+(zOffset + z)+")");
world.setBlock(id, xOffset + x, yOffset + y, zOffset + z);
}
}
}
}
}
}
public void generateMandelboxChunks(String name, int d, double scale, double cutoff, int itMin, int itMax, double tfmult,
int x1, int y1, int z1) {
// calculate the coordinates for the starting chunks
int xs = x1 / csz;
int ys = y1 / csz;
int zs = z1 / csz;
// calculate the coordinates for the ending chunks
int xe = (x1 + d) / csz;
int ye = (y1 + d) / csz;
int ze = (z1 + d) / csz;
// generate each chunk and set it in the world
Long time = System.currentTimeMillis();
DecimalFormat df = new DecimalFormat("#.##");
int totalChunks = (xe - xs + 1)*(ye - ys + 1)*(ze - zs + 1);
for (int x = xs; x <= xe; x++)
for (int y = ys; y <= ye; y++)
for (int z = zs; z <= ze; z++) {
world.setChunk(x, y, z, generateMandelboxChunk(name, d, scale, cutoff, itMin, itMax, tfmult,
x1, y1, z1, x - xs, y - ys, z - zs));
if ((System.currentTimeMillis() - time) > messageDelay) {
int currentChunks = (ze - zs + 1)*(ye - ys + 1)*(x - xs) + (ze - zs + 1)*(y - ys) + (z - zs);
double progress = (double) 100 * currentChunks/totalChunks;
System.out.println(df.format(progress)+"%");
time = System.currentTimeMillis();
}
}
}
// generate a single chunk that's part of a larger Menger Sponge
public Chunk generateMandelboxChunk(String name, int d, double scale, double cutoff, int itMin, int itMax, double tfmult,
int x1, int y1, int z1, int xc, int yc, int zc) {
// prepare the chunk and the palette
BytePalette p = world.getPalette(name);
Chunk c = new Chunk(csz);
double tfsub = tfmult / 2;
// here we calculate the upper limit in each Cartesian direction of the object
// that we're generating. this is important for us to not attempt to generate
// blocks outside of the object's actual dimensions
int x2 = x1 + d;
int y2 = y1 + d;
int z2 = z1 + d;
// we loop over the entire chunk, calculating Cartesian values relative to the
// origin of the fractal we're generating. we also calculate the real Cartesian
// values for each point to make sure we're in the range of the fractal we're
// generating.
for (int x = 0; x < csz; x++) {
int xRelative = xc * csz + x - (x1 % csz);
int xReal = xRelative + x1;
if ((xReal < x1) || (xReal > x2))
continue;
double xtf = (tfmult * (xRelative)) / (d - 1) - tfsub;
for (int y = 0; y < csz; y++) {
int yRelative = yc * csz + y - (y1 % csz);
int yReal = yRelative + y1;
if ((yReal < y1) || (yReal > y2))
continue;
double ytf = (tfmult * (yRelative)) / (d - 1) - tfsub;
for (int z = 0; z < csz; z++) {
int zRelative = zc * csz + z - (z1 % csz);
int zReal = zRelative + z1;
if ((zReal < z1) || (zReal > z2))
continue;
double ztf = (tfmult * (zRelative)) / (d - 1) - tfsub;
int iterations = -1;
double[] C = new double[] { xtf, ytf, ztf };
double[] Z = new double[] { 0, 0, 0 };
while ((mag(Z) < cutoff) && (iterations < itMax)) {
Z = add(mult(scale, boxformula(Z)), C);
iterations++;
}
if ((iterations >= itMin) && (iterations < itMax)) {
// place block if cutoff reached in itMin -> itMax range
if ((iterations >= itMin) && (iterations < itMax)) {
byte id = p.get(iterations - itMin);
c.setBlock(id, x, y, z);
}
}
}
}
}
return c;
}
// public void generateMandelboxChunks(String name, int d, double scale, double cutoff, int itMin, int itMax, double tfmult, int xo, int yo, int zo) {
// int xlim = (xo + d) / csz;
// int ylim = (yo + d) / csz;
// int zlim = (zo + d) / csz;
// int xs = xo / csz;
// int ys = yo / csz;
// int zs = zo / csz;
// int xm = d;
// int ym = d;
// int zm = d;
//
// int ixo = xo % csz;
// for (int i = xs; i <= xlim; i++) {
// int iyo = yo % csz;
// ym = d;
// zm = d;
// for (int j = ys; j <= ylim; j++) {
// int izo = zo % csz;
// zm = d;
// for (int k = zs; k <= zlim; k++) {
// Chunk c = generateMandelboxChunk(name, d, scale, cutoff, itMin, itMax, tfmult, ixo, iyo, izo, (i - xs) * csz, (j - ys) * csz, (k - zs) * csz, xm, ym, zm);
// world.setChunk(i, j, k, c);
// zm -= csz - izo;
// izo = 0;
// }
// ym -= csz - iyo;
// iyo = 0;
// }
// xm -= csz - ixo;
// ixo = 0;
// }
// }
//
// public Chunk generateMandelboxChunk(String name, int d, double scale, double cutoff, int itMin, int itMax, double tfmult, int xo, int yo, int zo, int cxo, int cyo, int czo, int xm, int ym, int zm) {
//
// Chunk chunk = new Chunk(64);
// double tfsub = tfmult / 2;
// BytePalette palette = world.getPalette(name);
//
// for (int x = 0; (x < 64 - xo) && (x < xm); x++) {
// double xc = (tfmult * (x + cxo)) / (d - 1) - tfsub;
// for (int y = 0; (y < 64 - yo) && (y < ym); y++) {
// double yc = (tfmult * (y + cyo)) / (d - 1) - tfsub;
// for (int z = 0; (z < 64 - zo) && (z < zm); z++) {
// double zc = (tfmult * (z + czo)) / (d - 1) - tfsub;
//
// int iterations = -1;
// double[] C = new double[] { xc, yc, zc };
// double[] Z = new double[] { 0, 0, 0 };
//
// while ((mag(Z) < cutoff) && (iterations < itMax)) {
// Z = add(mult(scale, boxformula(Z)), C);
// iterations++;
// }
//
// if ((iterations >= itMin) && (iterations < itMax)) {
// // place block if cutoff reached in itMin -> itMax range
// if ((iterations >= itMin) && (iterations < itMax)) {
// byte id = palette.get(iterations - itMin);
// chunk.setBlock(id, x + xo, y + yo, z + zo);
// }
// }
// }
// }
// }
//
// return chunk;
// }
// mandelbox vector growth formula
private double[] boxformula(double[] vec) {
double x = vec[0];
double y = vec[1];
double z = vec[2];
if (x > 1)
x = 2 - x;
else if (x < -1)
x = -2 - x;
if (y > 1)
y = 2 - y;
else if (y < -1)
y = -2 - y;
if (z > 1)
z = 2 - z;
else if (z < -1)
z = -2 - z;
double[] output = new double[] { x, y, z };
double m = mag(output);
if (m < 0.5)
output = mult(4, output);
else if (m < 1)
output = mult(1 / (m * m), output);
return output;
}
// multiplies a constant and a vector together
private double[] mult(double c, double[] vec) {
double[] output = new double[] { c * vec[0], c * vec[1], c * vec[2] };
return output;
}
/***************************************************************
********************* Greek Cross Methods *********************
***************************************************************/
// greek cross fractal
public void generateCross(byte id, int d0, int xOffset, int yOffset, int zOffset, int scale, int mode) {
// set recursion goal
if (recursionGoal == 0) {
recursionGoal = getCrossRecursions(d0, scale);
// System.out.println("Greek Cross recursion goal: "+recursionGoal);
time = System.currentTimeMillis();
}
// increment recursion counter
recursionCounter++;
// print recursion message once every messageDelay seconds
if (System.currentTimeMillis() - time > messageDelay) {
double recursionProgress = (double) 100 * (recursionCounter) / (recursionGoal);
DecimalFormat df = new DecimalFormat("#.##");
System.out.println(df.format(recursionProgress) + "%");
time = System.currentTimeMillis();
}
int d1 = (d0 - 1) / 2;
if ((floor(d1) - d1 != 0) || (d1 < scale))
return;
// make cross
if (mode != 1) {
for (int x = 0; x < d0; x++) {
if (x == d1)
continue;
world.setBlock(id, x + xOffset, d1 + yOffset, d1 + zOffset);
}
}
if (mode != 2) {
for (int y = 0; y < d0; y++) {
if (y == d1)
continue;
world.setBlock(id, d1 + xOffset, y + yOffset, d1 + zOffset);
}
}
if (mode != 3) {
for (int z = 0; z < d0; z++) {
if (z == d1)
continue;
world.setBlock(id, d1 + xOffset, d1 + yOffset, z + zOffset);
}
}
d1++;
// recursion close
generateCross(id, d1 - 1, 0 + xOffset, d1 / 2 + yOffset, d1 / 2 + zOffset, scale, 1);
generateCross(id, d1 - 1, d1 / 2 + xOffset, 0 + yOffset, d1 / 2 + zOffset, scale, 2);
generateCross(id, d1 - 1, d1 / 2 + xOffset, d1 / 2 + yOffset, 0 + zOffset, scale, 3);
// recursion far
generateCross(id, d1 - 1, d1 + xOffset, d1 / 2 + yOffset, d1 / 2 + zOffset, scale, 1);
generateCross(id, d1 - 1, d1 / 2 + xOffset, d1 + yOffset, d1 / 2 + zOffset, scale, 2);
generateCross(id, d1 - 1, d1 / 2 + xOffset, d1 / 2 + yOffset, d1 + zOffset, scale, 3);
}
private int getCrossRecursions(int d0, int scale) {
int recursions = 0;
int depth = 0;
while (d0 > scale) {
d0 /= 2;
depth++;
}
while (depth >= 0) {
recursions += pow(6, depth);
depth--;
}
return recursions;
}
/***************************************************************
********************* Octahedron Methods *********************
***************************************************************/
public void generateOctahedron(byte id, int d0, int xOffset, int yOffset, int zOffset, int oscale) {
// set recursion goal
if (recursionGoal == 0) {
recursionGoal = getCrossRecursions(d0, oscale);
// System.out.println("Greek Cross recursion goal: "+recursionGoal);
time = System.currentTimeMillis();
}
// increment recursion counter
recursionCounter++;
// print recursion message once every messageDelay seconds
if (System.currentTimeMillis() - time > messageDelay) {
double recursionProgress = (double) 100 * (recursionCounter) / (recursionGoal);
DecimalFormat df = new DecimalFormat("#.##");
System.out.println(df.format(recursionProgress) + "%");
time = System.currentTimeMillis();
}
int d1 = (d0 - 1) / 2;
int d2 = (d1 - 1) / 2;
// create octahedron when minimum scale reached
if (d1 < oscale) {
int width = 0;
for (int y = 0; y < d0; y++) {
for (int z = 0; z < d0; z++) {
for (int x = 0; x < d0; x++) {
if (abs(z - d1) + abs(x - d1) <= width) {
world.setBlock(id, x + xOffset, y + yOffset, z + zOffset);
}
}
}
if (y > d1 - 1)
width--;
else
width++;
}
} else { // recursion
generateOctahedron(id, d1, d2 + 1 + xOffset, d1 + 1 + yOffset, d2 + 1 + zOffset, oscale); // top octahedron
generateOctahedron(id, d1, d2 + 1 + xOffset, yOffset, d2 + 1 + zOffset, oscale); // bottom octahedron
generateOctahedron(id, d1, xOffset, d2 + 1 + yOffset, d2 + 1 + zOffset, oscale); // close right octahedron
generateOctahedron(id, d1, d2 + 1 + xOffset, d2 + 1 + yOffset, zOffset, oscale); // close left octahedron
generateOctahedron(id, d1, d2 + 1 + xOffset, d2 + 1 + yOffset, d1 + 1 + zOffset, oscale); // far right octahedron
generateOctahedron(id, d1, d1 + 1 + xOffset, d2 + 1 + yOffset, d2 + 1 + zOffset, oscale); // far left octahedron
}
}
}

View File

@ -10,10 +10,11 @@ public class Renderer {
private World world;
private Color SkyboxColor = Color.BLACK;
private double falloff = 4.0;
private double rate = 0.6;
private double rate = 2;
private double ambientIntensity = 0.2;
private double directionalIntensity = 0.3;
private int renderDistance = 8;
private int csz = 64;
public Camera camera;
// constructor
@ -56,7 +57,7 @@ public class Renderer {
double y1 = camera.y;
double z1 = camera.z;
int x2, y2, z2;
int cx1, cy1, cz1, cx2, cy2, cz2;
// int cx1, cy1, cz1, cx2, cy2, cz2;
double xs = Math.sin(pitch) * Math.cos(yaw) / castScale;
double ys = Math.sin(pitch) * Math.sin(yaw) / castScale;
@ -64,20 +65,20 @@ public class Renderer {
while (inBoundsC(x1, y1, z1)) {
// chunk processing
cx1 = (int) (x1 / 16.0);
cy1 = (int) (y1 / 16.0);
cz1 = (int) (z1 / 16.0);
if (world.getIsEmpty(cx1, cy1, cz1)) {
do {
x1 += xs;
y1 += ys;
z1 += zs;
cx2 = (int) (x1 / 16.0);
cy2 = (int) (y1 / 16.0);
cz2 = (int) (z1 / 16.0);
} while (cx1 == cx2 && cy1 == cy2 && cz1 == cz2);
continue;
}
// cx1 = (int) (x1 / 16.0);
// cy1 = (int) (y1 / 16.0);
// cz1 = (int) (z1 / 16.0);
// if (world.getIsEmpty(cx1, cy1, cz1)) {
// do {
// x1 += xs;
// y1 += ys;
// z1 += zs;
// cx2 = (int) (x1 / 16.0);
// cy2 = (int) (y1 / 16.0);
// cz2 = (int) (z1 / 16.0);
// } while (cx1 == cx2 && cy1 == cy2 && cz1 == cz2);
// continue;
// }
// block processing
byte block = world.getBlock(x1, y1, z1);
@ -101,10 +102,10 @@ public class Renderer {
}
private boolean inBoundsC(double x, double y, double z) {
int b = world.getSize() * 16;
int dx = ((int) Math.abs(camera.x - x)) / 16;
int dy = ((int) Math.abs(camera.y - y)) / 16;
int dz = ((int) Math.abs(camera.z - z)) / 16;
int b = world.getSize() * csz;
int dx = ((int) Math.abs(camera.x - x)) / csz;
int dy = ((int) Math.abs(camera.y - y)) / csz;
int dz = ((int) Math.abs(camera.z - z)) / csz;
return x >= 0 && x < b && y >= 0 && y < b && z >= 0 && z < b && dx < renderDistance && dy < renderDistance && dz < renderDistance;
}
@ -112,22 +113,10 @@ public class Renderer {
int[] mem = new int[width * height];
double yaw = camera.rotY;
double pitch = camera.rotX;
double[][] ref = new double[][] { { sin(pitch) * cos(yaw), sin(pitch) * sin(yaw), -cos(pitch) }, { -sin(yaw), cos(yaw), 0 }, // equal
// to
// cos(yaw
// +
// PI/2),
// sin(yaw
// +
// PI/2),
// 0
{ cos(pitch) * cos(yaw), cos(pitch) * sin(yaw), 2 * sin(pitch) } // cross
// product
// of
// the
// two
// vectors
// above
double[][] ref = new double[][] {
{ sin(pitch) * cos(yaw), sin(pitch) * sin(yaw), -cos(pitch) },
{ -sin(yaw), cos(yaw), 0 }, // equal to cos(yaw + PI/2), sin(yaw + PI/2), 0
{ cos(pitch) * cos(yaw), cos(pitch) * sin(yaw), 2 * sin(pitch) } // cross product of the two vectors above
};
// raycast for each pixel
@ -156,14 +145,13 @@ public class Renderer {
double fovH = camera.fovH / 2;
double fovV = camera.fovV / 2;
double yawr = ((px - w2) / w2) * fovH;
double pitchr = ((py - h2) / h2) * fovV; // correction because view
// window isn't 1:1
double pitchr = ((py - h2) / h2) * fovV; // correction because view window isn't 1:1
double x1 = camera.x;
double y1 = camera.y;
double z1 = camera.z;
int x2, y2, z2;
int cx1, cy1, cz1, cx2, cy2, cz2;
// int cx1, cy1, cz1, cx2, cy2, cz2;
double[] ray = new double[] { cos(pitchr) * cos(yawr), cos(pitchr) * sin(yawr), -sin(pitchr) };
ray = new double[] { ray[0] * ref[0][0] + ray[1] * ref[1][0] + ray[2] * ref[2][0], ray[0] * ref[0][1] + ray[1] * ref[1][1] + ray[2] * ref[2][1], ray[0] * ref[0][2] + ray[1] * ref[1][2] + ray[2] * ref[2][2], };
@ -173,20 +161,20 @@ public class Renderer {
while (inBoundsC(x1, y1, z1)) {
// chunk processing
cx1 = (int) (x1 / 16.0);
cy1 = (int) (y1 / 16.0);
cz1 = (int) (z1 / 16.0);
if (world.getIsEmpty(cx1, cy1, cz1)) {
do {
x1 += xs;
y1 += ys;
z1 += zs;
cx2 = (int) (x1 / 16.0);
cy2 = (int) (y1 / 16.0);
cz2 = (int) (z1 / 16.0);
} while (cx1 == cx2 && cy1 == cy2 && cz1 == cz2);
continue;
}
// cx1 = (int) (x1 / 16.0);
// cy1 = (int) (y1 / 16.0);
// cz1 = (int) (z1 / 16.0);
// if (world.getIsEmpty(cx1, cy1, cz1)) {
// do {
// x1 += xs;
// y1 += ys;
// z1 += zs;
// cx2 = (int) (x1 / 16.0);
// cy2 = (int) (y1 / 16.0);
// cz2 = (int) (z1 / 16.0);
// } while (cx1 == cx2 && cy1 == cy2 && cz1 == cz2);
// continue;
// }
// block processing
byte block = world.getBlock(x1, y1, z1);
@ -253,8 +241,7 @@ public class Renderer {
double x1 = camera.x;
double y1 = camera.y;
double z1 = camera.z;
int x2, y2, z2;
int cx1, cy1, cz1, cx2, cy2, cz2;
// int cx1, cy1, cz1;
double i1, i2, i3;
double[] ray = new double[] { cos(pitchr) * cos(yawr), cos(pitchr) * sin(yawr), -sin(pitchr) };
@ -275,31 +262,31 @@ public class Renderer {
z1 += (zs > 0) ? sv : -sv;
// chunk processing
cx1 = (int) (x1 / 16.0);
cy1 = (int) (y1 / 16.0);
cz1 = (int) (z1 / 16.0);
if (world.getIsEmpty(cx1, cy1, cz1)) {
i1 = (xs == 0) ? 999999999 : (xs > 0) ? abs((16.0 - x1 % 16.0) / xs) : abs((x1 % 16.0) / xs);
i2 = (ys == 0) ? 999999999 : (ys > 0) ? abs((16.0 - y1 % 16.0) / ys) : abs((y1 % 16.0) / ys);
i3 = (zs == 0) ? 999999999 : (zs > 0) ? abs((16.0 - z1 % 16.0) / zs) : abs((z1 % 16.0) / zs);
if ((i1 <= i2) && (i1 <= i3)) {
// step by i1
x1 += xs * (i1 + sv);
y1 += ys * (i1 + sv);
z1 += zs * (i1 + sv);
} else if ((i2 <= i1) && (i2 <= i3)) {
// step by i2
x1 += xs * (i2 + sv);
y1 += ys * (i2 + sv);
z1 += zs * (i2 + sv);
} else {
// step by i3
x1 += xs * (i3 + sv);
y1 += ys * (i3 + sv);
z1 += zs * (i3 + sv);
}
continue;
}
// cx1 = (int) (x1 / 16.0);
// cy1 = (int) (y1 / 16.0);
// cz1 = (int) (z1 / 16.0);
// if (world.getIsEmpty(cx1, cy1, cz1)) {
// i1 = (xs == 0) ? 999999999 : (xs > 0) ? abs((16.0 - x1 % 16.0) / xs) : abs((x1 % 16.0) / xs);
// i2 = (ys == 0) ? 999999999 : (ys > 0) ? abs((16.0 - y1 % 16.0) / ys) : abs((y1 % 16.0) / ys);
// i3 = (zs == 0) ? 999999999 : (zs > 0) ? abs((16.0 - z1 % 16.0) / zs) : abs((z1 % 16.0) / zs);
// if ((i1 <= i2) && (i1 <= i3)) {
// // step by i1
// x1 += xs * (i1 + sv);
// y1 += ys * (i1 + sv);
// z1 += zs * (i1 + sv);
// } else if ((i2 <= i1) && (i2 <= i3)) {
// // step by i2
// x1 += xs * (i2 + sv);
// y1 += ys * (i2 + sv);
// z1 += zs * (i2 + sv);
// } else {
// // step by i3
// x1 += xs * (i3 + sv);
// y1 += ys * (i3 + sv);
// z1 += zs * (i3 + sv);
// }
// continue;
// }
// block processing
byte block = world.getBlock(x1, y1, z1);
@ -368,9 +355,8 @@ public class Renderer {
}
try {
service.shutdown();
service.awaitTermination(10, TimeUnit.SECONDS);
service.awaitTermination(180, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (fb == null) {
@ -410,9 +396,9 @@ public class Renderer {
double startY = y;
double startZ = z;
double dx = ray[0] * renderDistance * 16;
double dy = ray[1] * renderDistance * 16;
double dz = ray[2] * renderDistance * 16;
double dx = ray[0] * renderDistance * csz;
double dy = ray[1] * renderDistance * csz;
double dz = ray[2] * renderDistance * csz;
double rayMagnitude = Math.sqrt(dx * dx + dy * dy + dz * dz);
@ -591,7 +577,10 @@ public class Renderer {
}
}
}
c = Renderer.this.CalculateColor(world.getType(block).getColor(), camera.x, x, camera.y, y, camera.z, z, result.getFace(), lightDot);
if (block != 0)
c = Renderer.this.CalculateColor(world.getType(block).getColor(), camera.x, x, camera.y, y, camera.z, z, result.getFace(), lightDot);
else
c = SkyboxColor;
} else {
c = SkyboxColor;
}

View File

@ -5,8 +5,11 @@ import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
@ -16,12 +19,17 @@ public class SwingInterface extends JPanel {
private static Keyboard keyboard = new Keyboard();
private Image src = null;
private World world;
private String worldName = "";
private Renderer renderer;
private Camera camera = new Camera(0, 0, 0, 0, 0, 0, Math.PI/2, Math.PI/5);
private Camera camera = new Camera(0, 0, 0, 0, 0, 0, Math.PI / 2, Math.PI / 6);
public double speed = 1.0;
private static String[] arguments;
private static final int X_SIZE = 800;
private static final int Y_SIZE = 600;
private static final int X_BIG = 1600;
private static final int Y_BIG = 1200;
private static final int csz = 64;
private static int pixelScale = 4;
private static int castScale = 4;
@ -30,15 +38,15 @@ public class SwingInterface extends JPanel {
public SwingInterface() {
new Worker().execute();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (src != null)
g.drawImage(src, 0, 0, this);
}
private class Worker extends SwingWorker<Void, Image> {
protected void process(List<Image> chunks) {
for (Image bufferedImage : chunks) {
src = bufferedImage;
@ -56,9 +64,12 @@ public class SwingInterface extends JPanel {
while (true) {
frames++;
if (frames == 30) {
// world.manageChunks((int) (camera.x / csz), (int) (camera.y / csz), (int) (camera.z / csz), false);
world.decompressAllChunks((int) (camera.x / csz), (int) (camera.y / csz), (int) (camera.z / csz));
double t = System.currentTimeMillis() - time;
double fps = 30 / (t / 1000);
System.out.println(((double) Math.round(fps * 100)/100) + "fps");
System.out.println("(" + ((int) camera.x) + "," + ((int) camera.y) + "," + ((int) camera.z) + ") "
+ ((double) Math.round(fps * 100) / 100) + "fps");
frames = 0;
time = System.currentTimeMillis();
}
@ -75,7 +86,8 @@ public class SwingInterface extends JPanel {
private void set_up() {
int worldSize = Integer.parseInt(arguments[0]);
int offset = (worldSize * 16 - Integer.parseInt(arguments[3]))/2;
int objectSize = Integer.parseInt(arguments[3]);
int offset = (worldSize * csz - objectSize) / 2;
world = new World(worldSize);
world.addColorBlockTypes();
world.addPalettes();
@ -83,94 +95,143 @@ public class SwingInterface extends JPanel {
if (arguments[1].equals("Menger Sponge")) {
System.out.println("Generating Menger Sponge...");
Byte b = (byte) world.getByteFromName(arguments[2]);
world.generateMengerSponge(b, Integer.parseInt(arguments[3]), offset, offset, offset);
// world.getGenerator().generateMengerSponge(b, objectSize, offset, offset, offset);
world.getGenerator().generateMengerChunks(b, objectSize, offset, offset, offset);
} else if (arguments[1].equals("Mandelbulb")) {
System.out.println("Generating Mandelbulb...");
world.generateMandelbulb(arguments[2], Integer.parseInt(arguments[3]), Double.parseDouble(arguments[6]), Double.parseDouble(arguments[8]), offset, offset, offset, Integer.parseInt(arguments[4]), Integer.parseInt(arguments[5]));
world.getGenerator().generateMandelbulb(arguments[2], objectSize,
Double.parseDouble(arguments[6]), Double.parseDouble(arguments[8]), offset, offset, offset,
Integer.parseInt(arguments[4]), Integer.parseInt(arguments[5]));
} else if (arguments[1].equals("Mandelbox")) {
System.out.println("Generating Mandelbox...");
world.generateMandelbox(arguments[2], Integer.parseInt(arguments[3]), Double.parseDouble(arguments[6]), Double.parseDouble(arguments[8]), Integer.parseInt(arguments[4]), Integer.parseInt(arguments[5]), Double.parseDouble(arguments[7]), offset, offset, offset);
// world.getGenerator().generateMandelbox(arguments[2], objectSize,
// Double.parseDouble(arguments[6]), Double.parseDouble(arguments[8]),
// Integer.parseInt(arguments[4]), Integer.parseInt(arguments[5]),
// Double.parseDouble(arguments[7]), offset, offset, offset);
world.getGenerator().generateMandelboxChunks(arguments[2], objectSize,
Double.parseDouble(arguments[6]), Double.parseDouble(arguments[8]),
Integer.parseInt(arguments[4]), Integer.parseInt(arguments[5]),
Double.parseDouble(arguments[7]), offset, offset, offset);
} else if (arguments[1].equals("Greek Cross")) {
System.out.println("Generating Greek Cross Fractal...");
Byte b = (byte) world.getByteFromName(arguments[2]);
world.generateCross(b, Integer.parseInt(arguments[3]), offset, offset, offset, Integer.parseInt(arguments[6]), 0);
world.getGenerator().generateCross(b, objectSize, offset, offset, offset,
Integer.parseInt(arguments[6]), 0);
// System.out.println(world.getGenerator().getCounter());
} else if (arguments[1].equals("Octahedron")) {
System.out.println("Generating Octahedron Fractal...");
Byte b = (byte) world.getByteFromName(arguments[2]);
world.generateOctahedron(b, Integer.parseInt(arguments[3]), offset, offset, offset, Integer.parseInt(arguments[6]));
world.getGenerator().generateOctahedron(b, objectSize, offset, offset, offset,
Integer.parseInt(arguments[6]));
// System.out.println(world.getGenerator().getCounter());
} else if (arguments[1].equals("Load")) {
System.out.println("Loading an existing world...");
world.load(arguments[6]);
world.load(arguments[2]);
}
System.out.println((Math.round((System.currentTimeMillis() - time)/10)/100.0)+" seconds spent generating world.");
time = System.currentTimeMillis();
world.updateIsEmptyAll();
System.out.println((Math.round((System.currentTimeMillis() - time)/10)/100.0)+" seconds spent updating isEmpty booleans.");
System.out.println((Math.round((System.currentTimeMillis() - time) / 10) / 100.0)
+ " seconds spent generating world.");
// world.setdsize(8);
world.setdmax(4);
world.initializeDecompression();
world.decompressAllChunks((int) (camera.x / csz), (int) (camera.y / csz), (int) (camera.z / csz));
// System.out.println("Compressing generated chunks...");
// time = System.currentTimeMillis();
// world.compressAll();
// System.out.println((Math.round((System.currentTimeMillis() - time) / 10) / 100.0)
// + " seconds spent compressing world.");
if (!arguments[1].equals("Load")) {
time = System.currentTimeMillis();
worldName = arguments[0] + "-" + arguments[1] + "-" + arguments[2] + "-" + arguments[3];
world.save(worldName + ".wrl");
System.out.println((Math.round((System.currentTimeMillis() - time) / 10) / 100.0)
+ " seconds spent saving world.");
}
camera.x = (double) (offset - 2.0);
camera.y = (double) (offset - 2.0);
camera.z = (double) (offset - 2.0);
camera.rotY = 0;
camera.rotX = Math.PI / 2;
renderer = new Renderer(world, camera);
System.out.println("World set up. Now rendering...");
}
private void process_input(double timestep) {
final int movement_scale = 15;
final int rotation_scale = 15;
if (keyboard.isKeyDown('A')) {
camera.x += timestep * movement_scale * Math.cos(camera.rotY - Math.PI / 2);
camera.y += timestep * movement_scale * Math.sin(camera.rotY - Math.PI / 2);
camera.x += speed * Math.cos(camera.rotY - Math.PI / 2);
camera.y += speed * Math.sin(camera.rotY - Math.PI / 2);
}
if (keyboard.isKeyDown('D')) {
camera.x += timestep * movement_scale * Math.cos(camera.rotY + Math.PI / 2);
camera.y += timestep * movement_scale * Math.sin(camera.rotY + Math.PI / 2);
camera.x += speed * Math.cos(camera.rotY + Math.PI / 2);
camera.y += speed * Math.sin(camera.rotY + Math.PI / 2);
}
if (keyboard.isKeyDown('W')) {
camera.x += timestep * movement_scale * Math.cos(camera.rotY);
camera.y += timestep * movement_scale * Math.sin(camera.rotY);
camera.x += speed * Math.cos(camera.rotY);
camera.y += speed * Math.sin(camera.rotY);
}
if (keyboard.isKeyDown('S')) {
camera.x += timestep * movement_scale * Math.cos(camera.rotY + Math.PI);
camera.y += timestep * movement_scale * Math.sin(camera.rotY + Math.PI);
camera.x += speed * Math.cos(camera.rotY + Math.PI);
camera.y += speed * Math.sin(camera.rotY + Math.PI);
}
if (keyboard.isKeyDown('Q')) {
camera.z -= timestep * movement_scale;
camera.z -= speed;
}
if (keyboard.isKeyDown('E')) {
camera.z += timestep * movement_scale;
camera.z += speed;
}
if (keyboard.isKeyDown('J')) {
camera.rotY -= timestep * rotation_scale * Math.PI / 32;
camera.rotY -= Math.PI / 32;
}
if (keyboard.isKeyDown('L')) {
camera.rotY += timestep * rotation_scale * Math.PI / 32;
camera.rotY += Math.PI / 32;
}
if (keyboard.isKeyDown('I')) {
camera.rotX += timestep * rotation_scale * Math.PI / 32;
camera.rotX += Math.PI / 32;
}
if (keyboard.isKeyDown('K')) {
camera.rotX -= timestep * rotation_scale * Math.PI / 32;
camera.rotX -= Math.PI / 32;
}
if (keyboard.isKeyDown('T')) {
if (keyboard.isKeyDown('=')) {
pixelScale++;
}
if (keyboard.isKeyDown('Y')) {
if (keyboard.isKeyDown('-')) {
pixelScale--;
}
if (keyboard.isKeyDown('G')) {
castScale++;
if (keyboard.isKeyDown('Z')) {
speed *= 0.90;
}
if (keyboard.isKeyDown('H')) {
castScale--;
if (keyboard.isKeyDown('X')) {
speed *= 1.11;
}
if (keyboard.isKeyDown('P')) { // P is for pretty
if (keyboard.isKeyDown('C')) {
System.out.println("Taking screenshot...");
try {
// retrieve image
Renderer r = new Renderer(world, camera);
Image scr = createImage(r.renderG(X_BIG, Y_BIG, 1, castScale, true));
BufferedImage bi = new BufferedImage(X_BIG, Y_BIG, BufferedImage.TYPE_INT_ARGB);
Graphics2D g3 = bi.createGraphics();
g3.drawImage(scr, 0, 0, null);
g3.dispose();
File outputfile = new File(worldName + "-"+Integer.toString((int) (Math.random()*1000))+".png");
ImageIO.write(bi, "png", outputfile);
r = null;
scr = null;
bi = null;
g3 = null;
} catch (IOException e) {
// nothing to do
}
}
if (keyboard.isKeyDown('P')) { // P is for pretty shadows
doShadows = true;
pixelScale = 1;
} else {
doShadows = false;
pixelScale = 4;
}
camera.rotY = camera.rotY % (Math.PI * 2);
camera.rotX = Math.max(Math.min(camera.rotX, Math.PI), 0);
@ -178,7 +239,7 @@ public class SwingInterface extends JPanel {
castScale = Math.max(Math.min(castScale, 50), 1);
}
}
public static void main(String[] args) {
arguments = args;
JFrame jf = new JFrame();

View File

@ -1,6 +1,8 @@
package voxelengine;
import java.awt.Color;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
@ -9,378 +11,351 @@ import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import static java.lang.Math.*;
public class World {
private static final int csz = 64; // chunk size
private int dsize = 8; // decompressed chunk space size
private int dmax = dsize/2; // maximum distance before decompressing additional chunks
private int size;
private Chunk[][][] chunks;
private boolean[][][] isEmpty;
private byte[][][][] cchunks;
private Chunk[][][] dchunks;
private BlockLibrary library = new BlockLibrary();
private ArrayList<BytePalette> palettes = new ArrayList<BytePalette>();
// constructor
private int xco = -100, yco = -100, zco = -100;
private ObjectGenerator generator = new ObjectGenerator(this, csz);
private Chunk emptyChunk = new Chunk(csz);
private byte[] emptyChunkC = compressChunk(emptyChunk);
public World(int size) {
super();
this.size = size;
this.chunks = new Chunk[size][size][size];
this.isEmpty = new boolean[size][size][size];
this.cchunks = new byte[size][size][size][];
// set cchunks to compressed empty chunks
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++) {
this.chunks[x][y][z] = new Chunk();
this.isEmpty[x][y][z] = false;
cchunks[x][y][z] = emptyChunkC.clone();
}
}
// methods
public int getSize() {
return size;
/***************************************************************
******************* System Variable Methods *******************
***************************************************************/
public void setdsize(int dsize) {
this.dsize = dsize;
}
// chunk/block methods
public void setdmax(int dmax) {
this.dmax = dmax;
}
/***************************************************************
********************* Chunk/Block Methods *********************
***************************************************************/
public Chunk getChunk(int x, int y, int z) {
if ((x < size && x >= 0) && (y < size && y >= 0) && (z < size && z >= 0))
return chunks[x][y][z];
else
return null;
int xa = x - this.xco;
int ya = y - this.yco;
int za = z - this.zco;
if ((xa >= 0) && (ya >= 0) && (za >= 0) && (xa < dsize) && (ya < dsize) && (za < dsize)) {
return dchunks[xa][ya][za];
} else {
return emptyChunk;
}
}
public byte getBlock(int x, int y, int z) {
int xChunk = x/16;
int yChunk = y/16;
int zChunk = z/16;
int xChunk = x / csz;
int yChunk = y / csz;
int zChunk = z / csz;
Chunk chunk = getChunk(xChunk, yChunk, zChunk);
if (chunk != null)
return chunk.getBlock(x % 16, y % 16, z % 16);
return chunk.getBlock(x % csz, y % csz, z % csz);
else
return 0;
}
public byte getBlock(double x, double y, double z) {
int xi = (int) x;
int yi = (int) y;
int zi = (int) z;
return getBlock(xi, yi, zi);
}
public void setBlock(byte id, int x, int y, int z) {
int xChunk = x/16;
int yChunk = y/16;
int zChunk = z/16;
Chunk chunk = getChunk(xChunk, yChunk, zChunk);
chunk.setBlock(id, x % 16, y % 16, z % 16);
public byte[] compressChunk(Chunk c) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
ObjectOutputStream out = new ObjectOutputStream(gzipOut);
out.writeObject(c);
out.close();
return baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void setChunk(int x, int y, int z, Chunk c) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream gzipOut = new GZIPOutputStream(baos);
ObjectOutputStream out = new ObjectOutputStream(gzipOut);
// if (c.checkIfEmpty())
// System.out.println("Chunk to be placed at ("+x+", "+y+", "+z+") is empty.");
out.writeObject(c);
out.close();
cchunks[x][y][z] = baos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
}
public void setBlock(byte id, int x, int y, int z) {
int xChunk = x / csz;
int yChunk = y / csz;
int zChunk = z / csz;
manageChunks(xChunk, yChunk, zChunk, true);
Chunk chunk = getChunk(xChunk, yChunk, zChunk);
chunk.setBlock(id, x % csz, y % csz, z % csz);
}
public void setBlock(byte id, double x, double y, double z) {
int xi = (int) x;
int yi = (int) y;
int zi = (int) z;
setBlock(id, xi, yi, zi);
}
// isEmpty methods
public boolean getIsEmpty(int x, int y, int z) {
return isEmpty[x][y][z];
public void manageChunks(int xc, int yc, int zc, boolean save) {
int xco = xc - (dsize / 2);
int yco = yc - (dsize / 2);
int zco = zc - (dsize / 2);
int xco_diff = this.xco - xco;
int yco_diff = this.yco - yco;
int zco_diff = this.zco - zco;
if ((abs(xco_diff) <= dmax) && (abs(yco_diff) <= dmax) && (abs(zco_diff) <= dmax))
return;
// set world offsets
this.xco = xco;
this.yco = yco;
this.zco = zco;
// move or decompress chunks
moveDecompressChunks(xco_diff, yco_diff, zco_diff, save);
}
public void updateIsEmpty(int x, int y, int z) {
Chunk chunk = getChunk(x, y, z);
isEmpty[x][y][z] = chunk.checkIfEmpty();
private void moveDecompressChunks(int xshift, int yshift, int zshift, boolean save) {
System.out.println("moveDecompressChunks("+xshift+", "+yshift+", "+zshift+")");
// save chunks
if (save) {
for (int x = 0; x < dsize; x++)
for (int y = 0; y < dsize; y++)
for (int z = 0; z < dsize; z++) {
if ((x + xco >= 0) && (y + yco >= 0) && (z + zco >= 0) && (x + xco < size) && (y + yco < size) && (z + zco < size))
setChunk(this.xco + x, this.yco + y, this.zco + z, dchunks[x][y][z]);
}
}
// x axis shift
if (xshift > 0) {
// positive shift on x-axis
for (int x = dsize - 1; x >= 0; x--)
for (int y = 0; y < dsize; y++)
for (int z = 0; z < dsize; z++) {
if (x < xshift) {
// System.out.println("Decompressing chunk at "+(this.xco + x + xshift)+","+(this.yco + y)+","+(this.zco + z));
dchunks[x][y][z] = decompressChunk(this.xco + x, this.yco + y, this.zco + z);
} else {
// System.out.println("Moving chunk from "+(x-xshift)+","+y+","+z+" to "+x+","+y+","+z);
dchunks[x][y][z] = dchunks[x - xshift][y][z];
}
}
} else if (xshift < 0) {
// negative shift on x-axis
for (int x = 0; x < dsize; x++)
for (int y = 0; y < dsize; y++)
for (int z = 0; z < dsize; z++) {
if (x >= dsize + xshift) {
// System.out.println("Decompressing chunk at "+(this.xco + x + xshift)+","+(this.yco + y)+","+(this.zco + z));
dchunks[x][y][z] = decompressChunk(this.xco + x, this.yco + y, this.zco + z);
} else {
// System.out.println("Moving chunk from "+(x-xshift)+","+y+","+z+" to "+x+","+y+","+z);
dchunks[x][y][z] = dchunks[x - xshift][y][z];
}
}
}
// y axis shift
if (yshift > 0) {
// positive shift on y-axis
for (int y = dsize - 1; y >= 0; y--)
for (int x = 0; x < dsize; x++)
for (int z = 0; z < dsize; z++) {
if (y < yshift) {
// System.out.println("Decompressing chunk at "+(this.xco + x)+","+(this.yco + y + yshift)+","+(this.zco + z));
dchunks[x][y][z] = decompressChunk(this.xco + x, this.yco + y, this.zco + z);
} else {
// System.out.println("Moving chunk from "+x+","+(y-yshift)+","+z+" to "+x+","+y+","+z);
dchunks[x][y][z] = dchunks[x][y - yshift][z];
}
}
} else if (yshift < 0) {
// negative shift on y-axis
for (int y = 0; y < dsize; y++)
for (int x = 0; x < dsize; x++)
for (int z = 0; z < dsize; z++) {
if (y >= dsize + yshift) {
// System.out.println("Decompressing chunk at "+(this.xco + x)+","+(this.yco + y + yshift)+","+(this.zco + z));
dchunks[x][y][z] = decompressChunk(this.xco + x, this.yco + y, this.zco + z);
} else {
// System.out.println("Moving chunk from "+x+","+(y-yshift)+","+z+" to "+x+","+y+","+z);
dchunks[x][y][z] = dchunks[x][y - yshift][z];
}
}
}
// z axis shift
if (zshift > 0) {
// positive shift on z-axis
for (int z = dsize - 1; z >= 0; z--)
for (int x = 0; x < dsize; x++)
for (int y = 0; y < dsize; y++) {
if (z < zshift) {
// System.out.println("Decompressing chunk at "+(this.xco + x)+","+(this.yco + y)+","+(this.zco + z + zshift));
dchunks[x][y][z] = decompressChunk(this.xco + x, this.yco + y, this.zco + z);
} else {
// System.out.println("Moving chunk from "+x+","+y+","+(z-zshift)+" to "+x+","+y+","+z);
dchunks[x][y][z] = dchunks[x][y][z - zshift];
}
}
} else if (zshift < 0) {
// negative shift on z-axis
for (int z = 0; z < dsize; z++)
for (int x = 0; x < dsize; x++)
for (int y = 0; y < dsize; y++) {
if (z >= dsize + zshift) {
// System.out.println("Decompressing chunk at "+(this.xco + x)+","+(this.yco + y)+","+(this.zco + z + zshift));
dchunks[x][y][z] = decompressChunk(this.xco + x, this.yco + y, this.zco + z);
} else {
// System.out.println("Moving chunk from "+x+","+y+","+(z-zshift)+" to "+x+","+y+","+z);
dchunks[x][y][z] = dchunks[x][y][z - zshift];
}
}
}
}
public void updateIsEmptyAll() {
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for (int z = 0; z < size; z++)
isEmpty[x][y][z] = getChunk(x,y,z).checkIfEmpty();
private Chunk decompressChunk(int x, int y, int z) {
Chunk c = emptyChunk;
if ((x >= 0) && (x < size) && (y >= 0) && (y < size) && (z >= 0) && (z < size)) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream(cchunks[x][y][z]);
GZIPInputStream gzipIn = new GZIPInputStream(bais);
ObjectInputStream objectIn = new ObjectInputStream(gzipIn);
c = (Chunk) objectIn.readObject();
objectIn.close();
} catch (Exception e) {
System.out.println(e);
}
}
return c;
}
// block type methods
public void decompressAllChunks(int xc, int yc, int zc) {
// System.out.println("decompressAllChunks("+xc+","+yc+","+zc+")");
int xco = xc - dsize / 2;
int yco = yc - dsize / 2;
int zco = zc - dsize / 2;
int xco_diff = xco - this.xco;
int yco_diff = yco - this.yco;
int zco_diff = zco - this.zco;
if ((xco_diff == 0) && (yco_diff == 0) && (zco_diff == 0))
return;
System.out.println("Decompressing all chunks...");
for (int x = 0; x < dsize; x++)
for (int y = 0; y < dsize; y++)
for (int z = 0; z < dsize; z++) {
dchunks[x][y][z] = decompressChunk(x + xco, y + yco, z + zco);
}
// set world offsets
this.xco = xco;
this.yco = yco;
this.zco = zco;
}
public void compressAll() {
for (int x = 0; x < dsize; x++)
for (int y = 0; y < dsize; y++)
for (int z = 0; z < dsize; z++) {
// System.out.println("Compressing chunk "+x+","+y+","+z);
if ((x + xco >= 0) && (y + yco >= 0) && (z + zco >= 0) && (x + xco < size) && (y + yco < size) && (z + zco < size))
setChunk(this.xco + x, this.yco + y, this.zco + z, dchunks[x][y][z]);
}
}
public void initializeDecompression() {
dchunks = null;
dchunks = new Chunk[dsize][dsize][dsize];
}
/***************************************************************
********************** BlockType Methods **********************
***************************************************************/
public void addType(BlockType type) {
library.addType(type);
}
public BlockType getType(byte id) {
return library.getType(id);
}
// world generation methods
public void generateMengerSponge(byte id, int d0, int xOffset, int yOffset, int zOffset) {
// place block and return if dimension = 1
if (d0 == 1) {
setBlock(id, xOffset, yOffset, zOffset);
return;
}
// 1/3 of dimension
int d1 = d0/3;
// recursion loop
for (int x = 0; x < 3; x++) {
for (int y = 0; y < 3; y++) {
if ((y == 1) && (x == 1))
continue;
for (int z = 0; z < 3; z++) {
if (((y == 1) && (z == 1)) || ((x == 1) && (z == 1)))
continue;
// recursion
if (d0 > 3)
generateMengerSponge(id, d1, x*d1 + xOffset, y*d1 + yOffset, z*d1 + zOffset);
else {
setBlock(id, x + xOffset, y + yOffset, z + zOffset);
}
}
}
}
}
public void generateBox(byte id, int d0, int xOffset, int yOffset, int zOffset) {
for (int x = 0; x < d0; x++) {
for (int y = 0; y < d0; y++) {
setBlock(id, x + xOffset, y + yOffset, zOffset);
setBlock(id, x + xOffset, y + yOffset, (d0 - 1) + zOffset);
}
}
for (int y = 0; y < d0; y++) {
for (int z = 0; z < d0; z++) {
setBlock(id, xOffset, y + yOffset, z + zOffset);
setBlock(id, (d0 - 1) + xOffset, y + yOffset, z + zOffset);
}
}
for (int x = 0; x < d0; x++) {
for (int z = 0; z < d0; z++) {
setBlock(id, x + xOffset, yOffset, z + zOffset);
setBlock(id, x + xOffset, (d0 - 1) + yOffset, z + zOffset);
}
}
}
// generate mandelbulb
public void generateMandelbulb(String name, int d, double power, double cutoff, int xOffset, int yOffset, int zOffset, int itMin, int itMax) {
BytePalette palette = getPalette(name);
//palette.printContents();
for (int x = 0; x < d; x++) {
double xc = tf(x, d);
for (int y = 0; y < d; y++) {
double yc = tf(y, d);
for (int z = 0; z < d; z++) {
double zc = tf(z, d);
int iterations = -1;
double[] C = new double[]{xc, yc, zc};
double[] Z = new double[]{0, 0, 0};
// iterate over vectors
while ((mag(Z) <= cutoff) && (iterations < itMax)) {
Z = add(formula(Z, power), C);
iterations++;
}
// place block if cutoff reached in itMin -> itMax range
if ((iterations >= itMin) && (iterations < itMax)) {
byte id = palette.get(iterations - itMin);
//System.out.println("Placing block "+id+" at ("+(xOffset + x)+","+(yOffset + y)+","+(zOffset + z)+")");
setBlock(id, xOffset + x, yOffset + y, zOffset + z);
}
}
}
}
}
private double tf(int v, int d) {
return (2.0 * v)/((double) d) - 1.0;
}
private double mag(double[] vec) {
return Math.sqrt(vec[0] * vec[0] + vec[1] * vec[1] + vec[2] * vec[2]);
}
private double[] add(double[] vec1, double[] vec2) {
return new double[]{vec1[0] + vec2[0], vec1[1] + vec2[1], vec1[2] + vec2[2]};
}
// mandelbulb vector growth formula
// if current vector magnitude > 1 and t is not too close to a multiple of (pi/2)
// this will give a vector of greater magnitude than the vector put in
// n, which is param, is the rate at which vector magnitude grows.
private double[] formula(double[] vec, double n) {
double t = theta(vec);
double p = phi(vec);
double k = Math.pow(mag(vec), n);
return new double[] {
k*Math.sin(n*t)*Math.cos(n*p),
k*Math.sin(n*t)*Math.sin(n*p),
k*Math.cos(n*t)};
public byte getByteFromName(String string) {
return library.getType(string).getId();
}
// theta vector value (arccos)
private double theta(double[] vec) {
return (Math.acos(vec[2]/(mag(vec) + 0.000000001)));
}
// phi vector value (arctan)
private double phi(double[] vec) {
return (Math.atan(vec[1]/(vec[0] + 0.000000001)));
}
// generate mandelbox
public void generateMandelbox(String name, int d, double scale, double cutoff, int itMin, int itMax, double tfmult, int xOffset, int yOffset, int zOffset) {
double tfsub = tfmult/2;
BytePalette palette = getPalette(name);
for (int x = 0; x < d; x++) {
double xc = (tfmult * x)/(d - 1) - tfsub;
for (int y = 0; y < d; y++) {
double yc = (tfmult * y)/(d - 1) - tfsub;
for (int z = 0; z < d; z++) {
double zc = (tfmult * z)/(d - 1) - tfsub;
/***************************************************************
***************** Library and Palette Methods *****************
***************************************************************/
int iterations = -1;
double[] C = new double[]{xc, yc, zc};
double[] Z = new double[]{0, 0, 0};
while ((mag(Z) < cutoff) && (iterations < itMax)) {
Z = add(mult(scale, boxformula(Z)), C);
iterations++;
}
if ((iterations >= itMin) && (iterations < itMax)) {
// place block if cutoff reached in itMin -> itMax range
if ((iterations >= itMin) && (iterations < itMax)) {
byte id = palette.get(iterations - itMin);
//System.out.println("Placing block "+id+" at ("+(xOffset + x)+","+(yOffset + y)+","+(zOffset + z)+")");
setBlock(id, xOffset + x, yOffset + y, zOffset + z);
}
}
}
}
}
}
// mandelbox vector growth formula
private double[] boxformula(double[] vec) {
double x = vec[0];
double y = vec[1];
double z = vec[2];
if (x > 1)
x = 2 - x;
else if (x < -1)
x = -2 - x;
if (y > 1)
y = 2 - y;
else if (y < -1)
y = -2 - y;
if (z > 1)
z = 2 - z;
else if (z < -1)
z = -2 - z;
double[] output = new double[]{x, y, z};
double m = mag(output);
if (m < 0.5)
output = mult(4, output);
else if (m < 1)
output = mult(1/(m*m), output);
return output;
}
// multiplies a constant and a vector together
private double[] mult(double c, double[] vec) {
double[] output = new double[]{
c * vec[0],
c * vec[1],
c * vec[2]};
return output;
}
// greek cross fractal
public void generateCross(byte id, int d0, int xOffset, int yOffset, int zOffset, int scale, int mode) {
int d1 = (d0 - 1)/2;
if ((Math.floor(d1) - d1 != 0) || (d1 < scale))
return;
// make cross
if (mode != 1) {
for (int x = 0; x < d0; x++) {
if (x == d1)
continue;
setBlock(id, x + xOffset, d1 + yOffset, d1 + zOffset);
}
}
if (mode != 2) {
for (int y = 0; y < d0; y++) {
if (y == d1)
continue;
setBlock(id, d1 + xOffset, y + yOffset, d1 + zOffset);
}
}
if (mode != 3) {
for (int z = 0; z < d0; z++) {
if (z == d1)
continue;
setBlock(id, d1 + xOffset, d1 + yOffset, z + zOffset);
}
}
d1++;
// recursion close
generateCross(id, d1 - 1, 0 + xOffset, d1/2 + yOffset, d1/2 + zOffset, scale, 1);
generateCross(id, d1 - 1, d1/2 + xOffset, 0 + yOffset, d1/2 + zOffset, scale, 2);
generateCross(id, d1 - 1, d1/2 + xOffset, d1/2 + yOffset, 0 + zOffset, scale, 3);
// recursion far
generateCross(id, d1 - 1, d1 + xOffset, d1/2 + yOffset, d1/2 + zOffset, scale, 1);
generateCross(id, d1 - 1, d1/2 + xOffset, d1 + yOffset, d1/2 + zOffset, scale, 2);
generateCross(id, d1 - 1, d1/2 + xOffset, d1/2 + yOffset, d1 + zOffset, scale, 3);
}
// octahedron fractal
public void generateOctahedron(byte id, int d0, int xOffset, int yOffset, int zOffset, int oscale) {
int d1 = (d0 - 1)/2;
int d2 = (d1 - 1)/2;
// create octahedron when minimum scale reached
if (d1 < oscale) {
int width = 0;
for (int y = 0; y < d0; y++) {
for (int z = 0; z < d0; z++) {
for (int x = 0; x < d0; x++) {
if (Math.abs(z - d1) + Math.abs(x - d1) <= width) {
setBlock(id, x + xOffset, y + yOffset, z + zOffset);
}
}
}
if (y > d1 - 1)
width--;
else
width++;
}
}
else { // recursion
generateOctahedron(id, d1, d2 + 1 + xOffset, d1 + 1 + yOffset, d2 + 1 + zOffset, oscale); // top octahedron
generateOctahedron(id, d1, d2 + 1 + xOffset, yOffset, d2 + 1 + zOffset, oscale); // bottom octahedron
generateOctahedron(id, d1, xOffset, d2 + 1 + yOffset, d2 + 1 + zOffset, oscale); // close right octahedron
generateOctahedron(id, d1, d2 + 1 + xOffset, d2 + 1 + yOffset, zOffset, oscale); // close left octahedron
generateOctahedron(id, d1, d2 + 1 + xOffset, d2 + 1 + yOffset, d1 + 1 + zOffset, oscale); // far right octahedron
generateOctahedron(id, d1, d1 + 1 + xOffset, d2 + 1 + yOffset, d2 + 1 + zOffset, oscale); // far left octahedron
}
}
// palettes and block types
public void addColorBlockTypes() {
library.addType(new BlockType(null, "red", 1, Color.RED));
library.addType(new BlockType(null, "green", 2, Color.GREEN));
library.addType(new BlockType(null, "neonGreen", 2, Color.GREEN));
library.addType(new BlockType(null, "blue", 3, Color.BLUE));
library.addType(new BlockType(null, "yellow", 4, Color.YELLOW));
library.addType(new BlockType(null, "orange", 5, Color.ORANGE));
library.addType(new BlockType(null, "gold", 5, Color.ORANGE));
library.addType(new BlockType(null, "magenta", 6, Color.MAGENTA));
library.addType(new BlockType(null, "pink", 7, Color.PINK));
library.addType(new BlockType(null, "cyan", 8, Color.CYAN));
library.addType(new BlockType(null, "black", 9, Color.BLACK));
library.addType(new BlockType(null, "black", 9, new Color(16, 16, 16)));
library.addType(new BlockType(null, "white", 10, Color.WHITE));
library.addType(new BlockType(null, "gray", 11, Color.GRAY));
library.addType(new BlockType(null, "darkGray", 12, Color.DARK_GRAY));
library.addType(new BlockType(null, "gloriousBlue", 13, new Color(7, 8, 114)));
library.addType(new BlockType(null, "watermelon", 14, new Color(247, 70, 122)));
library.addType(new BlockType(null, "gloriousViolet", 15, new Color(73, 8, 162)));
library.addType(new BlockType(null, "violet", 15, new Color(73, 8, 162)));
library.addType(new BlockType(null, "darkBlue", 16, new Color(14, 0, 42)));
library.addType(new BlockType(null, "brownPurple", 17, new Color(40, 0, 22)));
library.addType(new BlockType(null, "turquoise", 18, new Color(85, 135, 136)));
library.addType(new BlockType(null, "lightTurquoise", 19, new Color(136, 181, 178)));
library.addType(new BlockType(null, "chromeBlue", 19, new Color(136, 181, 178)));
library.addType(new BlockType(null, "klineWhite", 20, new Color(224, 225, 219)));
library.addType(new BlockType(null, "salmon", 21, new Color(255, 179, 158)));
library.addType(new BlockType(null, "rust", 22, new Color(183, 63, 38)));
@ -394,32 +369,74 @@ public class World {
library.addType(new BlockType(null, "seaGreen", 30, new Color(121, 189, 154)));
library.addType(new BlockType(null, "darkTurquoise", 31, new Color(59, 134, 134)));
library.addType(new BlockType(null, "royalBlue", 32, new Color(11, 72, 107)));
library.addType(new BlockType(null, "dryTurquoise", 33, new Color(124,150,125)));
library.addType(new BlockType(null, "dryOlive", 34, new Color(176,173,133)));
library.addType(new BlockType(null, "brown", 35, new Color(129,66,26)));
library.addType(new BlockType(null, "paleGold", 36, new Color(255,246,199)));
library.addType(new BlockType(null, "deepOlive", 37, new Color(55,52,18)));
library.addType(new BlockType(null, "redBrown", 38, new Color(153,77,37)));
library.addType(new BlockType(null, "brightMud", 39, new Color(73,51,6)));
library.addType(new BlockType(null, "royalTurquoise", 40, new Color(26,108,91)));
library.addType(new BlockType(null, "paleTurquoise", 41, new Color(60,151,112)));
library.addType(new BlockType(null, "leafGreen", 42, new Color(93,152,38)));
library.addType(new BlockType(null, "deepGreen", 43, new Color(15,85,69)));
library.addType(new BlockType(null, "blackTurquoise", 44, new Color(0,36,25)));
library.addType(new BlockType(null, "tropical", 45, new Color(50,205,141)));
library.addType(new BlockType(null, "dryGreen", 46, new Color(30,67,17)));
library.addType(new BlockType(null, "trueGreen", 47, new Color(46,169,37)));
library.addType(new BlockType(null, "rustRed", 48, new Color(226,109,64)));
library.addType(new BlockType(null, "brightCyan", 49, new Color(174,238,207)));
library.addType(new BlockType(null, "deepLavender", 50, new Color(158,126,154)));
library.addType(new BlockType(null, "manilla", 51, new Color(236,223,191)));
library.addType(new BlockType(null, "paleCrimson", 52, new Color(170,70,50)));
library.addType(new BlockType(null, "forestGreen", 53, new Color(67,134,38)));
library.addType(new BlockType(null, "forestGreen", 54, new Color(67,134,38)));
library.addType(new BlockType(null, "lavender", 55, new Color(171,138,185)));
library.addType(new BlockType(null, "strongBrown", 56, new Color(65,40,35)));
library.addType(new BlockType(null, "bronze", 57, new Color(211,125,12)));
}
public void addPalettes() {
palettes.add(new BytePalette("test", new byte[] { 10, 11, 12, 9, 1, 5, 4, 2, 8, 3, 6, 7 }));
palettes.add(new BytePalette("blackNblue", new byte[] { 10, 11, 12, 9, 3, 8, 10, 11, 12, 3, 8, 10 }));
palettes.add(new BytePalette("glory", new byte[] { 13, 14, 15, 16, 17, 13, 14, 15, 16, 17 }));
palettes.add(new BytePalette("boutique", new byte[] { 18, 19, 20, 21, 22, 18, 19, 20, 21, 22 }));
palettes.add(new BytePalette("goldfish", new byte[] { 23, 24, 25, 26, 27, 23, 24, 25, 26, 27 }));
palettes.add(new BytePalette("dreamy", new byte[] { 28, 29, 30, 31, 32, 28, 29, 30, 31, 32 }));
palettes.add(new BytePalette("Glory", new byte[] { 13, 14, 15, 16, 17, 13, 14, 15, 16, 17 }));
palettes.add(new BytePalette("Boutique", new byte[] { 18, 19, 20, 21, 22, 18, 19, 20, 21, 22 }));
palettes.add(new BytePalette("Goldfish", new byte[] { 23, 24, 25, 26, 27, 23, 24, 25, 26, 27 }));
palettes.add(new BytePalette("Dreamy", new byte[] { 28, 29, 30, 31, 32, 28, 29, 30, 31, 32 }));
palettes.add(new BytePalette("Technological", new byte[] { 10, 11, 12, 9, 3, 8, 10, 11, 12, 3, 8, 10 }));
palettes.add(new BytePalette("Murderous", new byte[] { 11, 12, 9, 1, 22, 26 }));
palettes.add(new BytePalette("Golddigger", new byte[] { 11, 12, 9, 5, 4, 53 }));
palettes.add(new BytePalette("Undergrowth", new byte[] { 11, 12, 9, 46, 47, 2 }));
palettes.add(new BytePalette("Feeling Blue", new byte[] { 49, 24, 23, 19, 18, 3, 32, 13 }));
palettes.add(new BytePalette("Oranje", new byte[] { 51, 21, 53, 26, 48, 27, 22 }));
palettes.add(new BytePalette("Tropical Sea", new byte[] { 36, 24, 19, 33, 41, 43, 44 }));
palettes.add(new BytePalette("Motherboard", new byte[] { 47, 46, 34, 4, 5, 36, 10, 11, 25 }));
palettes.add(new BytePalette("Fire in the Night", new byte[] { 9, 12, 11, 10, 5, 4, 27, 1, 22, 13 }));
palettes.add(new BytePalette("Sulfur", new byte[] { 5, 36, 33, 36, 37, 38, 39 }));
palettes.add(new BytePalette("Alien", new byte[] { 40, 9, 41, 42, 43, 44, 45, 46, 47 }));
palettes.add(new BytePalette("Fruit Shake", new byte[] { 50, 10, 49, 45, 33, 36, 51, 26, 27 }));
palettes.add(new BytePalette("Frosted Cactus", new byte[] { 53, 52, 41, 10, 36, 56, 54, 55 }));
}
public BytePalette getPalette(String name) {
for (int i = 0; i < palettes.size(); i++) {
if (palettes.get(i).getName().equals(name))
return palettes.get(i);
}
return null;
return palettes.get(0);
}
// load/save world
/***************************************************************
********************** Load/Save Methods **********************
***************************************************************/
public void load(String filename) {
System.out.println("Loading file " + filename);
try {
FileInputStream fis = new FileInputStream(filename);
GZIPInputStream gs = new GZIPInputStream(fis);
ObjectInputStream in = new ObjectInputStream(gs);
chunks = (Chunk[][][]) in.readObject();
cchunks = (byte[][][][]) in.readObject();
in.close();
fis.close();
} catch (Exception e) {
@ -432,7 +449,7 @@ public class World {
FileOutputStream fos = new FileOutputStream(filename);
GZIPOutputStream gz = new GZIPOutputStream(fos);
ObjectOutputStream out = new ObjectOutputStream(gz);
out.writeObject(chunks);
out.writeObject(cchunks);
out.flush();
out.close();
fos.close();
@ -441,7 +458,12 @@ public class World {
}
}
public byte getByteFromName(String string) {
return library.getType(string).getId();
public ObjectGenerator getGenerator() {
return generator;
}
public int getSize() {
return size;
}
}