diff --git a/VoxelEngine/.classpath b/VoxelEngine/.classpath
new file mode 100644
index 0000000..fb565a5
--- /dev/null
+++ b/VoxelEngine/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/VoxelEngine/.project b/VoxelEngine/.project
new file mode 100644
index 0000000..ff36af0
--- /dev/null
+++ b/VoxelEngine/.project
@@ -0,0 +1,17 @@
+
+
+ VoxelEngine
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/VoxelEngine/.settings/org.eclipse.jdt.core.prefs b/VoxelEngine/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..7341ab1
--- /dev/null
+++ b/VoxelEngine/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,11 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.7
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.7
diff --git a/VoxelEngine/bin/background.jpg b/VoxelEngine/bin/background.jpg
new file mode 100644
index 0000000..1955a05
Binary files /dev/null and b/VoxelEngine/bin/background.jpg differ
diff --git a/VoxelEngine/bin/game.au b/VoxelEngine/bin/game.au
new file mode 100644
index 0000000..e18f053
Binary files /dev/null and b/VoxelEngine/bin/game.au differ
diff --git a/VoxelEngine/bin/java.policy.applet b/VoxelEngine/bin/java.policy.applet
new file mode 100644
index 0000000..ba9f51d
--- /dev/null
+++ b/VoxelEngine/bin/java.policy.applet
@@ -0,0 +1,7 @@
+/* AUTOMATICALLY GENERATED ON Tue Apr 16 17:20:59 EDT 2002*/
+/* DO NOT EDIT */
+
+grant {
+ permission java.security.AllPermission;
+};
+
diff --git a/VoxelEngine/bin/menu.au b/VoxelEngine/bin/menu.au
new file mode 100644
index 0000000..6ee23bd
Binary files /dev/null and b/VoxelEngine/bin/menu.au differ
diff --git a/VoxelEngine/bin/store/Audioapp.class b/VoxelEngine/bin/store/Audioapp.class
new file mode 100644
index 0000000..246151f
Binary files /dev/null and b/VoxelEngine/bin/store/Audioapp.class differ
diff --git a/VoxelEngine/bin/store/SimpleImageLoad.class b/VoxelEngine/bin/store/SimpleImageLoad.class
new file mode 100644
index 0000000..1b76c80
Binary files /dev/null and b/VoxelEngine/bin/store/SimpleImageLoad.class differ
diff --git a/VoxelEngine/bin/voxelengine/Block.class b/VoxelEngine/bin/voxelengine/Block.class
new file mode 100644
index 0000000..c9af665
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/Block.class differ
diff --git a/VoxelEngine/bin/voxelengine/BlockLibrary.class b/VoxelEngine/bin/voxelengine/BlockLibrary.class
new file mode 100644
index 0000000..227ed66
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/BlockLibrary.class differ
diff --git a/VoxelEngine/bin/voxelengine/BlockType.class b/VoxelEngine/bin/voxelengine/BlockType.class
new file mode 100644
index 0000000..0f26d6d
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/BlockType.class differ
diff --git a/VoxelEngine/bin/voxelengine/Camera.class b/VoxelEngine/bin/voxelengine/Camera.class
new file mode 100644
index 0000000..bde7ad4
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/Camera.class differ
diff --git a/VoxelEngine/bin/voxelengine/Chunk.class b/VoxelEngine/bin/voxelengine/Chunk.class
new file mode 100644
index 0000000..3b20f8c
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/Chunk.class differ
diff --git a/VoxelEngine/bin/voxelengine/Keyboard.class b/VoxelEngine/bin/voxelengine/Keyboard.class
new file mode 100644
index 0000000..951665e
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/Keyboard.class differ
diff --git a/VoxelEngine/bin/voxelengine/Menu.class b/VoxelEngine/bin/voxelengine/Menu.class
new file mode 100644
index 0000000..5b7efdb
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/Menu.class differ
diff --git a/VoxelEngine/bin/voxelengine/Palette.class b/VoxelEngine/bin/voxelengine/Palette.class
new file mode 100644
index 0000000..a99233a
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/Palette.class differ
diff --git a/VoxelEngine/bin/voxelengine/Renderer.class b/VoxelEngine/bin/voxelengine/Renderer.class
new file mode 100644
index 0000000..19eff3c
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/Renderer.class differ
diff --git a/VoxelEngine/bin/voxelengine/SwingInterface$Worker.class b/VoxelEngine/bin/voxelengine/SwingInterface$Worker.class
new file mode 100644
index 0000000..699c112
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/SwingInterface$Worker.class differ
diff --git a/VoxelEngine/bin/voxelengine/SwingInterface.class b/VoxelEngine/bin/voxelengine/SwingInterface.class
new file mode 100644
index 0000000..8de70c7
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/SwingInterface.class differ
diff --git a/VoxelEngine/bin/voxelengine/World.class b/VoxelEngine/bin/voxelengine/World.class
new file mode 100644
index 0000000..81bce5f
Binary files /dev/null and b/VoxelEngine/bin/voxelengine/World.class differ
diff --git a/VoxelEngine/src/store/Audioapp.java b/VoxelEngine/src/store/Audioapp.java
new file mode 100644
index 0000000..828a91d
--- /dev/null
+++ b/VoxelEngine/src/store/Audioapp.java
@@ -0,0 +1,35 @@
+package store;
+
+import java.applet.*;
+import java.awt.*;
+import java.awt.event.*;
+
+public class Audioapp extends Applet implements ActionListener {
+ private AudioClip sound;
+ private Button playSound, loopSound, stopSound;
+
+ public void init() {
+ System.out.println(getCodeBase());
+ sound = getAudioClip(getCodeBase(), "menu.au");
+ playSound = new Button("Play");
+ playSound.addActionListener(this);
+ add(playSound);
+
+ loopSound = new Button("Loop");
+ loopSound.addActionListener(this);
+ add(loopSound);
+
+ stopSound = new Button("Stop");
+ stopSound.addActionListener(this);
+ add(stopSound);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+ if (e.getSource() == playSound)
+ sound.play();
+ else if (e.getSource() == loopSound)
+ sound.loop();
+ else if (e.getSource() == stopSound)
+ sound.stop();
+ }
+}
diff --git a/VoxelEngine/src/store/SimpleImageLoad.java b/VoxelEngine/src/store/SimpleImageLoad.java
new file mode 100644
index 0000000..14fdb1b
--- /dev/null
+++ b/VoxelEngine/src/store/SimpleImageLoad.java
@@ -0,0 +1,24 @@
+package store;
+
+import java.awt.*;
+import java.applet.*;
+import java.net.*;
+
+public class SimpleImageLoad extends Applet {
+ Image img;
+ URL coach;
+
+ public void init() {
+ try {
+ coach = new URL("http://www.cs.sbcc.cc.ca.us/~rhd/");
+ } catch (MalformedURLException e) {
+ showStatus("Exception: " + e.toString());
+ }
+
+ img = getImage(coach, "coach2c.gif");
+ }
+
+ public void paint(Graphics g) {
+ g.drawImage(img, 0, 0, this);
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/Block.java b/VoxelEngine/src/voxelengine/Block.java
new file mode 100644
index 0000000..4b92fcc
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/Block.java
@@ -0,0 +1,16 @@
+package voxelengine;
+
+public class Block {
+ private BlockType type;
+
+ // constructor
+ public Block(BlockType type) {
+ super();
+ this.type = type;
+ }
+
+ // getters
+ public BlockType getType() {
+ return type;
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/BlockLibrary.java b/VoxelEngine/src/voxelengine/BlockLibrary.java
new file mode 100644
index 0000000..1acc282
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/BlockLibrary.java
@@ -0,0 +1,20 @@
+package voxelengine;
+
+import java.util.ArrayList;
+
+public class BlockLibrary {
+ private ArrayList library = new ArrayList();
+
+ // methods
+ public void addType(BlockType type) {
+ library.add(type);
+ }
+ public BlockType getType(String id) {
+ for (int i = 0; i < library.size(); i++)
+ if ((library.get(i).getId().equals(id)) || (library.get(i).getName().equals(id)))
+ return library.get(i);
+
+ // if not found, return null
+ return null;
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/BlockType.java b/VoxelEngine/src/voxelengine/BlockType.java
new file mode 100644
index 0000000..1db62b1
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/BlockType.java
@@ -0,0 +1,34 @@
+package voxelengine;
+
+import java.awt.Color;
+import java.awt.Image;
+
+public class BlockType {
+ private Image texture;
+ private String name;
+ private String id;
+ private Color color;
+
+ // constructor
+ public BlockType(Image texture, String name, String id, Color color) {
+ super();
+ this.texture = texture;
+ this.name = name;
+ this.id = id;
+ this.color = color;
+ }
+
+ // getters
+ public Image getTexture() {
+ return texture;
+ }
+ public String getName() {
+ return name;
+ }
+ public String getId() {
+ return id;
+ }
+ public Color getColor() {
+ return color;
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/Camera.java b/VoxelEngine/src/voxelengine/Camera.java
new file mode 100644
index 0000000..d02a7de
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/Camera.java
@@ -0,0 +1,23 @@
+package voxelengine;
+
+public class Camera {
+ public double x;
+ public double y;
+ public double z;
+ public double rotX;
+ public double rotY;
+ public double rotZ;
+ public double fov;
+
+ // constructor
+ public Camera(double x, double y, double z, double rotY, double rotZ, double rotX, double fov) {
+ super();
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.rotX = rotX;
+ this.rotY = rotY;
+ this.rotZ = rotZ;
+ this.fov = fov;
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/Chunk.java b/VoxelEngine/src/voxelengine/Chunk.java
new file mode 100644
index 0000000..a397643
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/Chunk.java
@@ -0,0 +1,62 @@
+package voxelengine;
+
+public class Chunk {
+ private static int sz = 16;
+ private Block[][][] blocks = new Block[sz][sz][sz];
+
+ // methods
+ public void setBlock(BlockType type, int x, int y, int z) {
+ blocks[x][y][z] = new Block(type);
+ }
+ public Block getBlock(int x, int y, int z) {
+ return blocks[x][y][z];
+ }
+ 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] != null)
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ // saving and loading
+ public String saveChunk() {
+ // data header
+ String data = Integer.toString(sz) + "\n";
+
+ // save data
+ 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] != null)
+ data += blocks[x][y][z].getType().getId();
+ else
+ data += "0";
+ }
+ }
+ }
+
+ return data;
+ }
+ public void loadChunk(String data, BlockLibrary lib) throws Exception {
+ // first check if chunk sizes match
+ int size = Integer.parseInt(data.substring(0, data.indexOf("\n") - 1));
+ if (size != sz)
+ throw new Exception();
+
+ // then load data
+ for (int i = 0; i < data.length(); i++) {
+ if (data.charAt(i) == '0')
+ continue;
+ // calculate current 3d location
+ int z = (int) (i/(sz*sz));
+ int y = (int) ((i - z)/sz);
+ int x = i - z - y;
+ blocks[x][y][z] = new Block(lib.getType(String.valueOf(data.charAt(i))));
+ }
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/Keyboard.java b/VoxelEngine/src/voxelengine/Keyboard.java
new file mode 100644
index 0000000..4687a58
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/Keyboard.java
@@ -0,0 +1,23 @@
+package voxelengine;
+
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+
+public class Keyboard implements KeyListener {
+ private boolean[] keys = new boolean[65536];
+
+ public void keyTyped(KeyEvent e) {
+ }
+
+ public void keyPressed(KeyEvent e) {
+ keys[e.getKeyCode()] = true;
+ }
+
+ public void keyReleased(KeyEvent e) {
+ keys[e.getKeyCode()] = false;
+ }
+
+ public boolean isKeyDown(int key) {
+ return keys[key];
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/Menu.java b/VoxelEngine/src/voxelengine/Menu.java
new file mode 100644
index 0000000..bbbceb2
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/Menu.java
@@ -0,0 +1,303 @@
+package voxelengine;
+
+import java.applet.Applet;
+import java.applet.AudioClip;
+import java.awt.BorderLayout;
+import java.awt.Button;
+import java.awt.Choice;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.Image;
+import java.awt.Label;
+import java.awt.Panel;
+import java.awt.TextField;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+
+public class Menu extends Applet implements ActionListener, ItemListener {
+ private Button generateWorld, settings, quit, ok, back, generate;
+ private TextField size, worldSize, minIt, maxIt, power, zoom, cutoff;
+ private Label sizeL, colorL, worldSizeL, minItL, maxItL, powerL, zoomL, resL, pixL, castL, cutoffL;
+ private Choice choice, color;
+ private AudioClip sound;
+ private Image background;
+ private Panel pnl;
+
+ public void init() {
+ this.setSize(784, 562);
+ background = getImage(getCodeBase(), "background.jpg");
+ sound = getAudioClip(getCodeBase(), "menu.au");
+ sound.loop();
+ mainMenu();
+ }
+
+ public void paint(Graphics g) {
+ g.drawImage(background, 0, 0, this);
+ }
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Object src = e.getSource();
+ if (src == generateWorld) {
+ clearMenu();
+ generationMenu();
+ this.setSize(785, 562);
+ this.setSize(784, 562);
+ } else if (src == settings) {
+ clearMenu();
+ settingsMenu();
+ this.setSize(785, 562);
+ this.setSize(784, 562);
+ } else if (src == quit) {
+ clearMenu();
+ System.exit(0);
+ this.setSize(785, 562);
+ this.setSize(784, 562);
+ } else if (src == back) {
+ clearMenu();
+ mainMenu();
+ this.setSize(785, 562);
+ this.setSize(784, 562);
+ } else if (src == generate) {
+ sound.stop();
+ clearMenu();
+ this.setVisible(false);
+ sound = getAudioClip(getCodeBase(), "game.au");
+ sound.loop();
+ SwingInterface.main(new String[]{worldSize.getText(), choice.getSelectedItem(), color.getSelectedItem(), size.getText(), minIt.getText(), maxIt.getText(), power.getText(), zoom.getText(), cutoff.getText()});
+ }
+ }
+
+ public void clearMenu() {
+ this.removeAll();
+ repaint();
+ }
+
+ public void clearPanel() {
+ pnl.removeAll();
+ repaint();
+ }
+
+ public void generationMenu() {
+ pnl = new Panel();
+ pnl.setMaximumSize(new Dimension(350, 200));
+ pnl.setPreferredSize(new Dimension(350, 200));
+ pnl.setBackground(Color.BLACK);
+ worldSizeL = new Label("World size: ");
+ worldSizeL.setForeground(Color.LIGHT_GRAY);
+ worldSizeL.setBackground(Color.BLACK);
+ worldSizeL.setMaximumSize(new Dimension(70, 20));
+ worldSize = new TextField("20");
+ worldSize.setMaximumSize(new Dimension(50, 20));
+ choice = new Choice();
+ choice.addItem("Menger Sponge");
+ choice.addItem("Mandelbulb");
+ choice.addItem("Mandelbox");
+ choice.setMaximumSize(new Dimension(140, 40));
+ choice.setForeground(Color.LIGHT_GRAY);
+ choice.setBackground(Color.BLACK);
+ generate = new Button("Generate!");
+ generate.setMaximumSize(new Dimension(140, 40));
+ generate.setForeground(Color.LIGHT_GRAY);
+ generate.setBackground(Color.BLACK);
+ back = new Button("Back");
+ back.setMaximumSize(new Dimension(140, 40));
+ back.setForeground(Color.LIGHT_GRAY);
+ back.setBackground(Color.BLACK);
+ generate.addActionListener(this);
+ back.addActionListener(this);
+ choice.addItemListener(this);
+
+ this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+
+ this.add(Box.createRigidArea(new Dimension(0,30)));
+ add(worldSizeL);
+ add(worldSize);
+ this.add(Box.createRigidArea(new Dimension(0,20)));
+ add(choice);
+ this.add(Box.createRigidArea(new Dimension(0,30)));
+ add(pnl);
+ this.add(Box.createRigidArea(new Dimension(0,50)));
+ add(generate);
+ this.add(Box.createRigidArea(new Dimension(0,30)));
+ add(back);
+
+ colorL = new Label("Color: ");
+ colorL.setForeground(Color.LIGHT_GRAY);
+ colorL.setBackground(Color.BLACK);
+ colorL.setPreferredSize(new Dimension(50, 20));
+ color = new Choice();
+ color.setPreferredSize(new Dimension(80, 20));
+ sizeL = new Label("Size: ");
+ sizeL.setForeground(Color.LIGHT_GRAY);
+ sizeL.setBackground(Color.BLACK);
+ sizeL.setPreferredSize(new Dimension(40, 20));
+ size = new TextField("81");
+ size.setPreferredSize(new Dimension(50, 20));
+ minItL = new Label("Minimum Iterations: ");
+ minItL.setForeground(Color.LIGHT_GRAY);
+ minItL.setBackground(Color.BLACK);
+ minItL.setPreferredSize(new Dimension(120, 20));
+ minIt = new TextField("4");
+ minIt.setPreferredSize(new Dimension(100, 20));
+ maxItL = new Label("Maximum Iterations: ");
+ maxItL.setForeground(Color.LIGHT_GRAY);
+ maxItL.setBackground(Color.BLACK);
+ maxItL.setPreferredSize(new Dimension(120, 20));
+ maxIt = new TextField("16");
+ maxIt.setPreferredSize(new Dimension(100, 20));
+ powerL = new Label("Power: ");
+ powerL.setForeground(Color.LIGHT_GRAY);
+ powerL.setBackground(Color.BLACK);
+ powerL.setPreferredSize(new Dimension(50, 20));
+ power = new TextField("8");
+ power.setPreferredSize(new Dimension(50, 20));
+ zoomL = new Label("Zoom: ");
+ zoomL.setForeground(Color.LIGHT_GRAY);
+ zoomL.setBackground(Color.BLACK);
+ zoomL.setPreferredSize(new Dimension(50, 20));
+ zoom = new TextField("4");
+ zoom.setPreferredSize(new Dimension(50, 20));
+ cutoffL = new Label("Cutoff: ");
+ cutoffL.setForeground(Color.LIGHT_GRAY);
+ cutoffL.setBackground(Color.BLACK);
+ cutoffL.setPreferredSize(new Dimension(50, 20));
+ cutoff = new TextField("5");
+ cutoff.setPreferredSize(new Dimension(50, 20));
+
+ pnl.setLayout(new FlowLayout(FlowLayout.LEFT, 10, 10));
+
+ pnl.add(colorL, BorderLayout.CENTER);
+ pnl.add(color, BorderLayout.CENTER);
+ 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(zoomL, BorderLayout.CENTER);
+ pnl.add(zoom, BorderLayout.CENTER);
+ pnl.add(minItL, BorderLayout.CENTER);
+ pnl.add(minIt, BorderLayout.CENTER);
+ pnl.add(Box.createRigidArea(new Dimension(80,0)));
+ pnl.add(maxItL, BorderLayout.CENTER);
+ pnl.add(maxIt, BorderLayout.CENTER);
+ pnl.add(Box.createRigidArea(new Dimension(120,0)));
+ pnl.add(cutoffL, BorderLayout.CENTER);
+ pnl.add(cutoff, BorderLayout.CENTER);
+
+ mengerMenu();
+ }
+
+ public void mengerMenu() {
+ 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");
+ power.setEnabled(false);
+ zoom.setEnabled(false);
+ minIt.setEnabled(false);
+ maxIt.setEnabled(false);
+ cutoff.setEnabled(false);
+ }
+
+ public void bulbMenu() {
+ colorL.setText("Palette: ");
+ color.removeAll();
+ color.addItem("test");
+ color.addItem("blackNblue");
+ powerL.setText("Power: ");
+ power.setEnabled(true);
+ zoom.setEnabled(false);
+ minIt.setEnabled(true);
+ maxIt.setEnabled(true);
+ cutoff.setEnabled(true);
+ cutoff.setText("1024");
+ }
+
+ public void boxMenu() {
+ colorL.setText("Palette: ");
+ color.removeAll();
+ color.addItem("test");
+ color.addItem("blackNblue");
+ powerL.setText("Scale: ");
+ power.setEnabled(true);
+ zoom.setEnabled(true);
+ minIt.setEnabled(true);
+ maxIt.setEnabled(true);
+ cutoff.setEnabled(true);
+ cutoff.setText("5");
+ }
+
+ public void settingsMenu() {
+ back = new Button("Back");
+ back.setMaximumSize(new Dimension(140, 40));
+ back.setForeground(Color.LIGHT_GRAY);
+ back.setBackground(Color.BLACK);
+ back.addActionListener(this);
+
+ this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+
+ this.add(Box.createRigidArea(new Dimension(0,250)));
+ add(back, BorderLayout.CENTER);
+ }
+
+ public void mainMenu() {
+ generateWorld = new Button("Generate World");
+ generateWorld.setMaximumSize(new Dimension(140, 40));
+ generateWorld.setForeground(Color.LIGHT_GRAY);
+ generateWorld.setBackground(Color.BLACK);
+ settings = new Button("Settings");
+ settings.setMaximumSize(new Dimension(140, 40));
+ settings.setForeground(Color.LIGHT_GRAY);
+ settings.setBackground(Color.BLACK);
+ quit = new Button("Quit");
+ quit.setMaximumSize(new Dimension(140, 40));
+ quit.setForeground(Color.LIGHT_GRAY);
+ quit.setBackground(Color.BLACK);
+ generateWorld.addActionListener(this);
+ settings.addActionListener(this);
+ quit.addActionListener(this);
+
+ this.setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
+
+ this.add(Box.createRigidArea(new Dimension(0,170)));
+ add(generateWorld, BorderLayout.CENTER);
+ this.add(Box.createRigidArea(new Dimension(0,50)));
+ add(settings, BorderLayout.CENTER);
+ this.add(Box.createRigidArea(new Dimension(0,50)));
+ add(quit, BorderLayout.CENTER);
+ }
+
+ @Override
+ public void itemStateChanged(ItemEvent arg0) {
+ if (arg0.getSource() == choice) {
+ String sel = choice.getSelectedItem();
+ if (sel.equals("Menger Sponge")) {
+ mengerMenu();
+ } else if (sel.equals("Mandelbulb")) {
+ bulbMenu();
+ } else if (sel.equals("Mandelbox")){
+ boxMenu();
+ }
+ }
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/Palette.java b/VoxelEngine/src/voxelengine/Palette.java
new file mode 100644
index 0000000..8deb5ec
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/Palette.java
@@ -0,0 +1,25 @@
+package voxelengine;
+
+public class Palette {
+ private String name;
+ private String[] palette;
+
+ // constructor
+ public Palette(String name, String[] palette) {
+ super();
+ this.name = name;
+ this.palette = palette;
+ }
+
+ // methods
+ public String get(int index) {
+ return palette[index];
+ }
+ public String getName() {
+ return name;
+ }
+ public void printContents() {
+ for (int i = 0; i < palette.length; i++)
+ System.out.println(get(i));
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/Renderer.java b/VoxelEngine/src/voxelengine/Renderer.java
new file mode 100644
index 0000000..c4ad9d9
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/Renderer.java
@@ -0,0 +1,266 @@
+package voxelengine;
+
+import java.awt.Color;
+import java.awt.image.MemoryImageSource;
+
+public class Renderer {
+ private World world;
+ private Color SkyboxColor = Color.BLACK;
+ private double falloff = 8.0;
+ private double rate = 0.85;
+ private int renderDistance = 8;
+ public Camera camera;
+
+ // constructor
+ public Renderer(World world, Camera camera) {
+ super();
+ this.world = world;
+ this.camera = camera;
+ }
+
+ // rendering methods
+ public MemoryImageSource render(int width, int height, int pixelScale, int castScale) {
+ int[] mem = new int[width*height];
+
+ // raycast for each pixel
+ for (int py = 0; py < height - pixelScale; py += pixelScale) {
+ for (int px = 0; px < width - pixelScale; px += pixelScale) {
+ if (pixelScale == 1)
+ mem[px + py * width] = raycast(px, py, width, height, castScale);
+ else {
+ int val = raycast(px, py, width, height, castScale);
+ for (int pys = 0; pys < pixelScale; ++pys) {
+ for (int pxs = 0; pxs < pixelScale; ++pxs) {
+ mem[px + pxs + (py + pys) * width] = val;
+ }
+ }
+ }
+ }
+ }
+
+ // return image source
+ return new MemoryImageSource(width, height, mem, 0, width);
+ }
+
+ private int raycast(int px, int py, int width, int height, int castScale) {
+ double w2 = width/2;
+ double h2 = height/2;
+ double yaw = camera.rotY + ((px - w2) / w2) * Math.PI / 4;
+ double pitch = camera.rotX + ((py - h2) / h2) * Math.PI / 4;
+
+ double x1 = camera.x;
+ double y1 = camera.y;
+ double z1 = camera.z;
+ int x2, y2, z2;
+
+ double xs = Math.sin(pitch) * Math.cos(yaw) / castScale;
+ double ys = Math.sin(pitch) * Math.sin(yaw) / castScale;
+ double zs = Math.cos(pitch) / castScale;
+
+ while (inBoundsC(x1, y1, z1)) {
+ Block block = world.getBlock(x1, y1, z1);
+ if (block != null) {
+ Color c = block.getType().getColor();
+ c = CalculateColor(c, camera.x, x1, camera.y, y1, camera.z, z1);
+ return c.getRGB();
+ }
+ x2 = (int) x1;
+ y2 = (int) y1;
+ z2 = (int) z1;
+ do {
+ x1 += xs;
+ y1 += ys;
+ z1 += zs;
+ } while ((int) x1 == x2 && (int) y1 == y2 && (int) z1 == z2);
+ }
+
+ return SkyboxColor.getRGB();
+ }
+
+ @SuppressWarnings("unused")
+ private boolean inBounds(double x, double y, double z) {
+ int b = world.getSize() * 16;
+ return x >= 0 && x < b && y >= 0 && y < b && z >= 0 && z < b;
+ }
+
+ public MemoryImageSource renderC(int width, int height, int pixelScale, int castScale) {
+ int[] mem = new int[width*height];
+
+ // raycast for each pixel
+ for (int py = 0; py < height - pixelScale; py += pixelScale) {
+ for (int px = 0; px < width - pixelScale; px += pixelScale) {
+ if (pixelScale == 1)
+ mem[px + py * width] = raycastC(px, py, width, height, castScale);
+ else {
+ int val = raycastC(px, py, width, height, castScale);
+ for (int pys = 0; pys < pixelScale; ++pys) {
+ for (int pxs = 0; pxs < pixelScale; ++pxs) {
+ mem[px + pxs + (py + pys) * width] = val;
+ }
+ }
+ }
+ }
+ }
+
+ // return image source
+ return new MemoryImageSource(width, height, mem, 0, width);
+ }
+
+ private int raycastC(int px, int py, int width, int height, int castScale) {
+ double w2 = width/2;
+ double h2 = height/2;
+ double yaw = camera.rotY + ((px - w2) / w2) * Math.PI / 4;
+ double pitch = camera.rotX + ((py - h2) / h2) * Math.PI / 4;
+
+ double x1 = camera.x;
+ double y1 = camera.y;
+ double z1 = camera.z;
+ int x2, y2, z2;
+ 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;
+ double zs = Math.cos(pitch) / castScale;
+
+ 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;
+ }
+
+ // block processing
+ Block block = world.getBlock(x1, y1, z1);
+ if (block != null) {
+ Color c = block.getType().getColor();
+ c = CalculateColor(c, camera.x, x1, camera.y, y1, camera.z, z1);
+ return c.getRGB();
+ }
+
+ x2 = (int) x1;
+ y2 = (int) y1;
+ z2 = (int) z1;
+ do {
+ x1 += xs;
+ y1 += ys;
+ z1 += zs;
+ } while ((int) x1 == x2 && (int) y1 == y2 && (int) z1 == z2);
+ }
+
+ return SkyboxColor.getRGB();
+ }
+
+ 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;
+ return x >= 0 && x < b && y >= 0 && y < b && z >= 0 && z < b && dx < renderDistance && dy < renderDistance && dz < renderDistance;
+ }
+
+ public MemoryImageSource renderD(int width, int height, int pixelScale, int castScale) {
+ int[] mem = new int[width*height];
+
+ // raycast for each pixel
+ for (int py = 0; py < height - pixelScale; py += pixelScale) {
+ for (int px = 0; px < width - pixelScale; px += pixelScale) {
+ if (pixelScale == 1)
+ mem[px + py * width] = raycastD(px, py, width, height, castScale);
+ else {
+ int val = raycastD(px, py, width, height, castScale);
+ for (int pys = 0; pys < pixelScale; ++pys) {
+ for (int pxs = 0; pxs < pixelScale; ++pxs) {
+ mem[px + pxs + (py + pys) * width] = val;
+ }
+ }
+ }
+ }
+ }
+
+ // return image source
+ return new MemoryImageSource(width, height, mem, 0, width);
+ }
+
+ private int raycastD(int px, int py, int width, int height, int castScale) {
+ double w2 = width/2;
+ double h2 = height/2;
+ double yaw = camera.rotY + ((px - w2) / w2) * Math.PI / 4;
+ double pitch = camera.rotX + ((py - h2) / h2) * Math.PI / 4;
+ yaw = (pitch < 0 || pitch > Math.PI) ? (yaw + Math.PI) % (2*Math.PI): yaw;
+ pitch = (pitch < 0) ? Math.abs(pitch) : pitch;
+ pitch = (pitch > Math.PI) ? 2*Math.PI - pitch : pitch;
+
+ double x1 = camera.x;
+ double y1 = camera.y;
+ double z1 = camera.z;
+ int x2, y2, z2;
+ 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;
+ double zs = Math.cos(pitch) / castScale;
+
+ 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;
+ }
+
+ // block processing
+ Block block = world.getBlock(x1, y1, z1);
+ if (block != null) {
+ Color c = block.getType().getColor();
+ c = CalculateColor(c, camera.x, x1, camera.y, y1, camera.z, z1);
+ return c.getRGB();
+ }
+
+ x2 = (int) x1;
+ y2 = (int) y1;
+ z2 = (int) z1;
+ do {
+ x1 += xs;
+ y1 += ys;
+ z1 += zs;
+ } while ((int) x1 == x2 && (int) y1 == y2 && (int) z1 == z2);
+ }
+
+ return SkyboxColor.getRGB();
+ }
+
+ private Color CalculateColor(Color c, double x1, double x2, double y1, double y2, double z1, double z2) {
+ double distance = Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) + Math.pow(z1 - z2, 2));
+ double lightIntensity = falloff/Math.pow(distance, rate);
+
+ // calculate color components
+ int red = (int) (c.getRed() * lightIntensity);
+ red = (red > 255) ? 255 : red;
+ int green = (int) (c.getGreen() * lightIntensity);
+ green = (green > 255) ? 255 : green;
+ int blue = (int) (c.getBlue() * lightIntensity);
+ blue = (blue > 255) ? 255 : blue;
+
+ // return calculated color
+ return new Color(red, green, blue);
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/SwingInterface.java b/VoxelEngine/src/voxelengine/SwingInterface.java
new file mode 100644
index 0000000..732cc66
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/SwingInterface.java
@@ -0,0 +1,165 @@
+package voxelengine;
+
+import java.applet.AudioClip;
+import java.awt.BorderLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.SwingWorker;
+
+@SuppressWarnings("serial")
+public class SwingInterface extends JPanel {
+ private static Keyboard keyboard = new Keyboard();
+ private Image src = null;
+ private World world;
+ private Renderer renderer;
+ private Camera camera = new Camera(0, 0, 0, 0, 0, 0, Math.PI/2);
+ private static String[] arguments;
+
+ private static final int X_SIZE = 800;
+ private static final int Y_SIZE = 600;
+ private static int pixelScale = 4;
+ private static int castScale = 4;
+
+ 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 {
+
+ protected void process(List chunks) {
+ for (Image bufferedImage : chunks) {
+ src = bufferedImage;
+ repaint();
+ }
+ }
+
+ protected Void doInBackground() throws Exception {
+ set_up();
+ int frames = 0;
+ long time = System.currentTimeMillis();
+
+ while (true) {
+ frames++;
+ if (frames == 30) {
+ double t = System.currentTimeMillis() - time;
+ double fps = 30 / (t / 1000);
+ System.out.println(((double) Math.round(fps * 100)/100) + "fps");
+ frames = 0;
+ time = System.currentTimeMillis();
+ }
+ process_input();
+ Image img = createImage(renderer.renderC(X_SIZE, Y_SIZE, pixelScale, castScale));
+ BufferedImage buffer = new BufferedImage(X_SIZE, Y_SIZE, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2 = buffer.createGraphics();
+ g2.drawImage(img, 0, 0, null);
+ g2.dispose();
+ publish(buffer);
+ }
+ }
+
+ private void set_up() {
+ int worldSize = Integer.parseInt(arguments[0]);
+ int offset = (worldSize * 16 - Integer.parseInt(arguments[3]))/2;
+ world = new World(worldSize);
+ world.addColorBlockTypes();
+ world.addPalettes();
+ long time = System.currentTimeMillis();
+ if (arguments[1].equals("Menger Sponge")) {
+ System.out.println("Generating Menger Sponge...");
+ world.generateMengerSponge(arguments[2], Integer.parseInt(arguments[3]), 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]));
+ } 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);
+ }
+ 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.");
+ 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() {
+ if (keyboard.isKeyDown('A')) {
+ camera.x += Math.cos(camera.rotY - Math.PI / 2);
+ camera.y += Math.sin(camera.rotY - Math.PI / 2);
+ }
+ if (keyboard.isKeyDown('D')) {
+ camera.x += Math.cos(camera.rotY + Math.PI / 2);
+ camera.y += Math.sin(camera.rotY + Math.PI / 2);
+ }
+ if (keyboard.isKeyDown('W')) {
+ camera.x += Math.cos(camera.rotY);
+ camera.y += Math.sin(camera.rotY);
+ }
+ if (keyboard.isKeyDown('S')) {
+ camera.x += Math.cos(camera.rotY + Math.PI);
+ camera.y += Math.sin(camera.rotY + Math.PI);
+ }
+ if (keyboard.isKeyDown('Q')) {
+ camera.z -= 1;
+ }
+ if (keyboard.isKeyDown('E')) {
+ camera.z += 1;
+ }
+ if (keyboard.isKeyDown('J')) {
+ camera.rotY -= Math.PI / 32;
+ }
+ if (keyboard.isKeyDown('L')) {
+ camera.rotY += Math.PI / 32;
+ }
+ if (keyboard.isKeyDown('I')) {
+ camera.rotX -= Math.PI / 32;
+ }
+ if (keyboard.isKeyDown('K')) {
+ camera.rotX += Math.PI / 32;
+ }
+ if (keyboard.isKeyDown('T')) {
+ pixelScale++;
+ }
+ if (keyboard.isKeyDown('Y')) {
+ pixelScale--;
+ }
+ if (keyboard.isKeyDown('G')) {
+ castScale++;
+ }
+ if (keyboard.isKeyDown('H')) {
+ castScale--;
+ }
+ camera.rotY = camera.rotY % (Math.PI * 2);
+ camera.rotX = Math.max(Math.min(camera.rotX, Math.PI), 0);
+ pixelScale = Math.max(Math.min(pixelScale, 10), 1);
+ castScale = Math.max(Math.min(castScale, 50), 1);
+ }
+ }
+
+ public static void main(String[] args) {
+ arguments = args;
+ JFrame jf = new JFrame();
+ jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ jf.addKeyListener(keyboard);
+ jf.getContentPane().add(new SwingInterface(), BorderLayout.CENTER);
+ jf.setSize(X_SIZE, Y_SIZE);
+ jf.setVisible(true);
+ }
+}
diff --git a/VoxelEngine/src/voxelengine/World.java b/VoxelEngine/src/voxelengine/World.java
new file mode 100644
index 0000000..d058af4
--- /dev/null
+++ b/VoxelEngine/src/voxelengine/World.java
@@ -0,0 +1,353 @@
+package voxelengine;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.Random;
+
+public class World {
+ private int size;
+ private Chunk[][][] chunks;
+ private boolean[][][] isEmpty;
+ private BlockLibrary library = new BlockLibrary();
+ private ArrayList palettes = new ArrayList();
+
+ // constructor
+ public World(int size) {
+ super();
+ this.size = size;
+ this.chunks = new Chunk[size][size][size];
+ this.isEmpty = new boolean[size][size][size];
+
+ 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;
+ }
+ }
+
+ // methods
+ public int getSize() {
+ return size;
+ }
+
+ // 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;
+ }
+ public Block getBlock(int x, int y, int z) {
+ int xChunk = x/16;
+ int yChunk = y/16;
+ int zChunk = z/16;
+ Chunk chunk = getChunk(xChunk, yChunk, zChunk);
+ if (chunk != null)
+ return chunk.getBlock(x % 16, y % 16, z % 16);
+ else
+ return null;
+ }
+ public Block 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(String 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);
+ BlockType type = getType(id);
+ chunk.setBlock(type, x % 16, y % 16, z % 16);
+ }
+ public void setBlock(String 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 updateIsEmpty(int x, int y, int z) {
+ Chunk chunk = getChunk(x, y, z);
+ isEmpty[x][y][z] = chunk.checkIfEmpty();
+ }
+ 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();
+ }
+
+ // block type methods
+ public void addType(BlockType type) {
+ library.addType(type);
+ }
+ public BlockType getType(String id) {
+ return library.getType(id);
+ }
+
+ // world generation methods
+ public void generateMengerSponge(String 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(String 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);
+ }
+ }
+ }
+
+ public void generateBensWorld() {
+ for (int i = 0; i < 100; ++i) {
+ Random r = new Random(i);
+ for (int j = 0; j < 100; ++j) {
+ setBlock("blue", i, j, 0);
+ if ((i + j) % 2 == 0)
+ setBlock("red", i, 0, j);
+ else
+ setBlock("black", i, 0, j);
+ setBlock("orange", 0, i, j);
+ setBlock("cyan", i, j, 50);
+ setBlock("yellow", i, 99, j);
+ setBlock("pink", 99, i, j);
+
+ if (i % 4 == 0) {
+ int rand = r.nextInt(100);
+ if (rand < 10)
+ setBlock("green", i, 70, j);
+ else if (rand < 50)
+ setBlock("gray", i, 70, j);
+ else
+ setBlock("darkGray", i, 70, j);
+ } else if (i % 2 == 0)
+ setBlock("black", i, 70, j);
+ }
+ }
+ }
+
+ // generate mandelbulb
+ public void generateMandelbulb(String name, int d, double power, double cutoff, int xOffset, int yOffset, int zOffset, int itMin, int itMax) {
+ Palette 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)) {
+ String 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)};
+ }
+
+ // 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;
+ Palette 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;
+
+ 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)) {
+ String 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;
+ }
+
+ // 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, "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, "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, "white", "A", Color.WHITE));
+ library.addType(new BlockType(null, "gray", "B", Color.GRAY));
+ library.addType(new BlockType(null, "darkGray", "C", Color.DARK_GRAY));
+ }
+
+ public void addPalettes() {
+ palettes.add(new Palette("test", new String[]{"white", "gray", "darkGray", "black", "red", "orange", "yellow", "green", "cyan", "blue", "magenta", "pink"}));
+ palettes.add(new Palette("blackNblue", new String[]{"white", "gray", "darkGray", "black", "blue", "cyan", "white", "gray", "darkGray", "blue", "cyan", "white"}));
+ }
+
+ public Palette getPalette(String name) {
+ for (int i = 0; i < palettes.size(); i++) {
+ if (palettes.get(i).getName().equals(name))
+ return palettes.get(i);
+ }
+ return null;
+ }
+
+ // load/save world
+ public void load(String filename) {
+
+ }
+ public void save(String filename) {
+
+ }
+}