diff --git a/pom.xml b/pom.xml
index 890b24d9..786ec3db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -100,14 +100,6 @@
commons-crypto
1.1.0
-
-
-
-
- electrosphere
- TerrainGen
- 0.1
-
diff --git a/src/main/java/electrosphere/game/state/LoadingThread.java b/src/main/java/electrosphere/game/state/LoadingThread.java
index 832a6343..e8b1d730 100644
--- a/src/main/java/electrosphere/game/state/LoadingThread.java
+++ b/src/main/java/electrosphere/game/state/LoadingThread.java
@@ -382,7 +382,7 @@ public class LoadingThread extends Thread {
// }
- for(int i = 0; i < 50; i++){
+ for(int i = 0; i < 10; i++){
Random rand = new Random();
String treePath = "Models/tree1.fbx";
Entity tree = EntityUtils.spawnDrawableEntity(treePath);
diff --git a/src/main/java/electrosphere/game/terrain/TerrainManager.java b/src/main/java/electrosphere/game/terrain/TerrainManager.java
index f7c09fbf..a86edada 100644
--- a/src/main/java/electrosphere/game/terrain/TerrainManager.java
+++ b/src/main/java/electrosphere/game/terrain/TerrainManager.java
@@ -2,8 +2,8 @@ package electrosphere.game.terrain;
import com.google.gson.Gson;
import electrosphere.main.Globals;
-import electrosphere.terraingen.TerrainGen;
-import electrosphere.terraingen.models.TerrainModel;
+import electrosphere.game.terrain.generation.TerrainGen;
+import electrosphere.game.terrain.generation.models.TerrainModel;
import electrosphere.util.Utilities;
import java.io.File;
import java.io.IOException;
diff --git a/src/main/java/electrosphere/game/terrain/generation/Continent.java b/src/main/java/electrosphere/game/terrain/generation/Continent.java
new file mode 100644
index 00000000..80d9e07b
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/Continent.java
@@ -0,0 +1,17 @@
+package electrosphere.game.terrain.generation;
+
+/**
+ *
+ * @author satellite
+ */
+class Continent {
+ public int dim_x;
+ public int dim_y;
+ public int size = 0;
+ public int[][] elevation;
+ public int[][] chart_Precipitation;
+ public int[][] chart_Temperature;
+ public int[][] chart_Climate;
+ public int[][] chart_Wind_Macro;
+ public Region[][] regions;
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/Hotspot.java b/src/main/java/electrosphere/game/terrain/generation/Hotspot.java
new file mode 100644
index 00000000..6fb58aa5
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/Hotspot.java
@@ -0,0 +1,144 @@
+package electrosphere.game.terrain.generation;
+
+/**
+ *
+ * @author satellite
+ */
+class Hotspot {
+
+ int x;
+ int y;
+ int life_current;
+ int life_max;
+ int magnitude_current;
+ int magnitude_max;
+ TerrainGenerator parent;
+
+
+ public Hotspot(int x, int y, int life_max, int magnitude, TerrainGenerator parent) {
+ this.x = x;
+ this.y = y;
+ this.life_current = 0;
+ this.life_max = life_max;
+ this.magnitude_current = 1;
+ this.magnitude_max = magnitude;
+ this.parent = parent;
+ }
+
+ public void simulate() {
+ if ((1.0f - (Math.abs((life_max / 2) - life_current) / (life_max / 2))) > 0.8f) {
+ magnitude_current = magnitude_max;
+ } else if ((1.0f - (Math.abs((life_max / 2) - life_current) / (life_max / 2))) > 0.6f) {
+ magnitude_current = (int) (0.8f * magnitude_max);
+ } else if ((1.0f - (Math.abs((life_max / 2) - life_current) / (life_max / 2))) > 0.4f) {
+ magnitude_current = (int) (0.6f * magnitude_max);
+ } else if ((1.0f - (Math.abs((life_max / 2) - life_current) / (life_max / 2))) > 0.2f) {
+ magnitude_current = (int) (0.4f * magnitude_max);
+ } else {
+ magnitude_current = (int) (0.2f * magnitude_max);
+ }
+ //affect asthenosphere heat
+ if (magnitude_current == 1) {
+ parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ } else if (magnitude_current == 2) {
+ parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (y + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (y - 1 >= 0) {
+ parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ } else if (magnitude_current == 3) {
+ parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (y + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ }
+ if (y - 1 >= 0) {
+ parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ }
+ } else if (magnitude_current == 4) {
+ parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (y + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ }
+ if (y - 1 >= 0) {
+ parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ }
+ } else if (magnitude_current == 5) {
+ parent.asthenosphere_Heat[x][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (y + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y + 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ }
+ if (y - 1 >= 0) {
+ parent.asthenosphere_Heat[x][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ if (x + 1 < parent.DIMENSION) {
+ parent.asthenosphere_Heat[x + 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ if (x - 1 >= 0) {
+ parent.asthenosphere_Heat[x - 1][y - 1] = (int) (100.0f - Math.abs((life_max / 2) - life_current) * 100 / (life_max / 2));
+ }
+ }
+ }
+ life_current++;
+ }
+ public void add_to_elevation(int x, int y, int magnitude){
+ parent.elevation[x][y] = parent.elevation[x][y] + magnitude;
+ if(parent.elevation[x][y] > 100){
+ parent.elevation[x][y] = 100;
+ }
+ }
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/InterpolationDisplay.java b/src/main/java/electrosphere/game/terrain/generation/InterpolationDisplay.java
new file mode 100644
index 00000000..f69b9a3b
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/InterpolationDisplay.java
@@ -0,0 +1,218 @@
+package electrosphere.game.terrain.generation;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import javax.swing.JPanel;
+
+/**
+ *
+ * @author satellite
+ */
+class InterpolationDisplay extends JPanel{
+ @Override
+ public void paint(Graphics g) {
+ if(TerrainGen.display_toggle == 0) {
+ for (int x = 0; x < TerrainGen.DIMENSION; x++) {
+ for (int y = 0; y < TerrainGen.DIMENSION; y++) {
+ if (TerrainGen.mountain_parsed[x][y] > TerrainGen.mountain_Threshold - 1) {
+ g.setColor(new Color((int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1, 1));
+ } else if (TerrainGen.ocean_parsed[x][y] > TerrainGen.ocean_Threshold - 1) {
+ g.setColor(
+ new Color(
+ 1,
+ (int) ((TerrainGen.elevation[x][y] + 50) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ (int) ((TerrainGen.elevation[x][y] + 50) / 100.0 * 254 * (TerrainGen.brightness / 100.0))
+ )
+ );
+ } else {
+ g.setColor(new Color(1, (int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1));
+ }
+ g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2);
+ }
+ }
+ } else if(TerrainGen.display_toggle == 1){
+ for (int x = 0; x < TerrainGen.DIMENSION; x++) {
+ for (int y = 0; y < TerrainGen.DIMENSION; y++) {
+ if (TerrainGen.precipitation_Chart[x][y] > 0) {
+ g.setColor(
+ new Color(
+ 1,
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0))
+ )
+ );
+ } else {
+ g.setColor(new Color((int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1, 1));
+ }
+ g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2);
+ }
+ }
+ } else if(TerrainGen.display_toggle == 2){
+ for (int x = 0; x < TerrainGen.DIMENSION; x++) {
+ for (int y = 0; y < TerrainGen.DIMENSION; y++) {
+// if (TerrainInterpolator.precipitation_Chart[x][y] > 0) {
+ g.setColor(
+ new Color(
+ (int) ((TerrainGen.temperature_Chart[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ 1
+ )
+ );
+// } else {
+// g.setColor(new Color((int) (TerrainInterpolator.elevation[x][y] / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)), 1, 1));
+// }
+ g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2);
+ }
+ }
+ } else if(TerrainGen.display_toggle == 3){
+ for (int x = 0; x < TerrainGen.DIMENSION; x++) {
+ for (int y = 0; y < TerrainGen.DIMENSION; y++) {
+ if (TerrainGen.climate_category[x][y] == 0) {
+ g.setColor(Color.BLUE);
+// g.setColor(
+// new Color(
+// 1,
+// (int) ((TerrainInterpolator.elevation[x][y]) / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)),
+// (int) ((TerrainInterpolator.elevation[x][y]) / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0))
+// )
+// );
+ } else if(TerrainGen.climate_category[x][y] == 1){
+ g.setColor(Color.RED);
+// g.setColor(
+// new Color(
+// 1,
+// (int) ((TerrainInterpolator.elevation[x][y]) / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)),
+// 1
+// )
+// );
+ } else if(TerrainGen.climate_category[x][y] == 2){
+ g.setColor(Color.GREEN);
+// g.setColor(
+// new Color(
+// 1,
+// (int) ((TerrainInterpolator.elevation[x][y]) / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)),
+// 1
+// )
+// );
+ } else if(TerrainGen.climate_category[x][y] == 3){
+ g.setColor(Color.YELLOW);
+// g.setColor(
+// new Color(
+// 1,
+// 1,
+// (int) ((TerrainInterpolator.elevation[x][y]) / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0))
+// )
+// );
+ } else if(TerrainGen.climate_category[x][y] == 4){
+ g.setColor(
+ new Color(
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ 1
+ )
+ );
+ g.setColor(Color.ORANGE);
+ } else if(TerrainGen.climate_category[x][y] == 5){
+ g.setColor(
+ new Color(
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ 1,
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0))
+ )
+ );
+ g.setColor(Color.BLACK);
+ } else if(TerrainGen.climate_category[x][y] == 6){
+ g.setColor(
+ new Color(
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0)),
+ (int) ((TerrainGen.elevation[x][y]) / 100.0 * 254 * (TerrainGen.brightness / 100.0))
+ )
+ );
+ } else {
+ g.setColor(new Color((int) (TerrainGen.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1, 1));
+ }
+ g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2);
+ }
+ }
+ } else if(TerrainGen.display_toggle == 4){
+ for (int x = 0; x < TerrainGen.DIMENSION; x++) {
+ for (int y = 0; y < TerrainGen.DIMENSION; y++) {
+ if (TerrainGen.continent_Number[x][y] > 8) {
+ g.setColor(Color.PINK);
+ } else if (TerrainGen.continent_Number[x][y] > 7) {
+ g.setColor(Color.DARK_GRAY);
+ } else if (TerrainGen.continent_Number[x][y] > 6) {
+ g.setColor(Color.CYAN);
+ } else if (TerrainGen.continent_Number[x][y] > 5) {
+ g.setColor(Color.GRAY);
+ } else if (TerrainGen.continent_Number[x][y] > 4) {
+ g.setColor(Color.orange);
+ } else if (TerrainGen.continent_Number[x][y] > 3) {
+ g.setColor(Color.green);
+ } else if (TerrainGen.continent_Number[x][y] > 2) {
+ g.setColor(Color.yellow);
+ } else if (TerrainGen.continent_Number[x][y] > 1) {
+ g.setColor(Color.blue);
+ } else if (TerrainGen.continent_Number[x][y] > 0) {
+ g.setColor(Color.red);
+ } else {
+ g.setColor(Color.BLACK);
+ }
+ g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2);
+ }
+ }
+ } else if (TerrainGen.display_toggle == 5) {
+ Continent current = TerrainGen.continents.get(TerrainGen.current_Continent);
+ g.drawString("dim_x: " + current.dim_x, 20, 20);
+ g.drawString("dim_y: " + current.dim_y, 20, 30);
+ for (int x = 0; x < current.dim_x; x++) {
+ for (int y = 0; y < current.dim_y; y++) {
+ if (current.elevation[x][y] > 10) {
+ g.setColor(new Color(1, (int) (current.elevation[x][y] / 100.0 * 254 * (TerrainGen.brightness / 100.0)), 1));
+ g.fillRect(50 + x * 2, 50 + y * 2, 2, 2);
+ }
+ }
+ }
+ } else if (TerrainGen.display_toggle == 6){
+ Continent current = TerrainGen.continents.get(TerrainGen.current_Continent);
+ for(int x = 0; x < Region.REGION_DIMENSION; x++){
+ for(int y = 0; y < Region.REGION_DIMENSION; y++){
+ if(current.regions[TerrainGen.current_Region_X][TerrainGen.current_Region_Y].chart_Drainage[x][y] > 0){
+ g.setColor(Color.BLUE);
+ } else {
+ g.setColor(Color.BLACK);
+ }
+ g.fillRect(50 + x * 2, 50 + y * 2, 2, 2);
+ }
+ }
+ }
+// if(TerrainInterpolator.display_toggle == 0) {
+// g.drawString("Elevation Raws", 10, 10);
+// for (int x = 0; x < 100; x++) {
+// for (int y = 0; y < 100; y++) {
+// g.setColor(new Color(1, (int) (TerrainInterpolator.elevation[x][y] / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)), 1));
+// g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2);
+// }
+// }
+// } else if(TerrainInterpolator.display_toggle == 1) {
+// g.drawString("Parsed Mountains", 10, 10);
+// for (int x = 0; x < 100; x++) {
+// for (int y = 0; y < 100; y++) {
+// if(TerrainInterpolator.mountain_parsed[x][y] > TerrainInterpolator.mountain_Threshold - 1){
+// g.setColor(new Color((int) (TerrainInterpolator.elevation[x][y] / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)), 1, 1));
+// } else {
+// g.setColor(new Color(1, (int) (TerrainInterpolator.elevation[x][y] / 100.0 * 254 * (TerrainInterpolator.brightness / 100.0)), 1));
+// }
+// g.fillRect(x * 2 + 25, y * 2 + 25, 2, 2);
+// }
+// }
+// } else if(TerrainInterpolator.display_toggle == 2){
+// g.drawString("Oceans", 10, 10);
+// } else if(TerrainInterpolator.display_toggle == 3){
+// g.drawString("Continents", 10, 10);
+// } else if(TerrainInterpolator.display_toggle == 4){
+// g.drawString("Temperatures", 10, 10);
+// }
+ }
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/MidoceanicRidge.java b/src/main/java/electrosphere/game/terrain/generation/MidoceanicRidge.java
new file mode 100644
index 00000000..48391107
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/MidoceanicRidge.java
@@ -0,0 +1,9 @@
+package electrosphere.game.terrain.generation;
+
+/**
+ *
+ * @author satellite
+ */
+class MidoceanicRidge {
+
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/Region.java b/src/main/java/electrosphere/game/terrain/generation/Region.java
new file mode 100644
index 00000000..ee4d7f2a
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/Region.java
@@ -0,0 +1,19 @@
+package electrosphere.game.terrain.generation;
+
+/**
+ *
+ * @author satellite
+ */
+class Region {
+ public static int REGION_DIMENSION = 100;
+ int chart_Elevation[][];
+ int chart_Drainage[][];
+ int chart_Max_Water_Flow[][];
+ int elevation_Goal;
+ Region neighbors[][];
+ public boolean finished_Drainage_Simulation = false;
+ public Region(){
+ neighbors = new Region[3][3];
+ neighbors[1][1] = null;
+ }
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/TerrainGen.java b/src/main/java/electrosphere/game/terrain/generation/TerrainGen.java
new file mode 100644
index 00000000..f06b5fd5
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/TerrainGen.java
@@ -0,0 +1,1416 @@
+package electrosphere.game.terrain.generation;
+
+import electrosphere.game.terrain.generation.models.TerrainModel;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.swing.JFrame;
+
+/**
+ *
+ * @author satellite
+ */
+public class TerrainGen {
+ public static int elevation[][];
+ public static int DIMENSION = 100;
+ //the interpolation ratio applied to the statically generated terrain
+ static int interpolationRatio = 10;
+ //vertical static interpolation ratio
+ static int verticalInterpolationRatio = 10;
+ //the interpolation ratio applied to the dynamically generated terrain per chunk
+ static int dynamicInterpRatio = 1000;
+ static JFrame frame = new JFrame();
+ static InterpolationDisplay graphics = new InterpolationDisplay();
+ public static int brightness = 0;
+ static int brightness_hold_incrementer = 0;
+ static boolean brightness_increasing = true;
+ public static int display_toggle = 0;
+ static final int max_Display_Toggle = 6;
+
+ public static int mountain_parsed[][];
+ static final int mountain_Threshold = 75;
+ static final int mountain_Range_Size_Minimum = 10;
+
+ public static int ocean_parsed[][];
+ static final int ocean_Threshold = 25;
+
+ static Vector wind_field[][];
+
+ public static int[][] precipitation_Chart;
+ static final int rain_Shadow_Blocker_Height = 80;
+
+ public static int[][] temperature_Chart;
+
+ public static long[][] chunkRandomizer;
+
+ /*
+ 0 - ocean
+ 1 - tropical
+ 2 - subtropical
+ 3 - temperate
+ 4 - dry
+ 5 - polar
+ 6 - mountainous
+ */
+ public static int[][] climate_category;
+
+ public static int num_Continents = 0;
+ public static int[][] continent_Number;
+
+ public static ArrayList continents = new ArrayList();
+
+ public static int current_Continent = 1;
+ public static int current_Region_X = 0;
+ public static int current_Region_Y = 0;
+
+ public static void main(String args[]){
+
+ TerrainGenerator tergen = new TerrainGenerator();
+ tergen.set_Dimension(DIMENSION);
+ tergen.set_Lifespan(15000);
+ tergen.run();
+ elevation = tergen.get_Terrain();
+
+
+ elevation = interpolate_Elevation_Raws(elevation);
+ DIMENSION = DIMENSION * 2;
+
+ elevation = compression_filter(elevation);
+ elevation = three_halves_filter(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = small_Kernel_Sharpen(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = three_halves_filter(elevation);
+ elevation = small_Kernel_Smooth(elevation);
+ elevation = small_Kernel_Sharpen(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = land_exponential_filter(elevation);
+ elevation = land_exponential_filter(elevation);
+ elevation = land_exponential_filter(elevation);
+ elevation = land_exponential_filter(elevation);
+
+ mountain_parsed = new int[DIMENSION][DIMENSION];
+ ocean_parsed = new int[DIMENSION][DIMENSION];
+ continent_Number = new int[DIMENSION][DIMENSION];
+
+ mountain_parsed = parse_Mountainscapes(elevation);
+
+ ocean_parsed = parse_Oceans(elevation);
+
+ wind_field = map_Wind_Field();
+
+ precipitation_Chart = calculate_Rain_Shadows(elevation,ocean_parsed,wind_field);
+
+ temperature_Chart = generate_Temperature_Chart();
+
+ climate_category = infer_Climate_Category();
+
+ determine_Continents();
+
+ fill_Continents();
+
+ //for display tbh
+ anchor_To_Real_Region();
+
+
+ display_toggle = 0;
+
+ create_Frame();
+
+ while(true){
+ if(brightness_increasing){
+ if(brightness < 100){
+ brightness++;
+ } else {
+ }
+ } else {
+ if(brightness > 0){
+ brightness--;
+ } else {
+ brightness_increasing = true;
+ display_toggle++;
+ if(display_toggle > 1){
+ display_toggle = 0;
+ }
+ }
+ }
+ frame.repaint();
+ Utilities.sleep(10);
+ }
+ }
+
+ public TerrainModel generateModel(){
+ TerrainModel rVal;
+
+ TerrainGenerator tergen = new TerrainGenerator();
+ tergen.set_Dimension(DIMENSION);
+ tergen.set_Lifespan(15000);
+ tergen.run();
+ elevation = tergen.get_Terrain();
+
+
+ elevation = interpolate_Elevation_Raws(elevation);
+ DIMENSION = DIMENSION * 2;
+
+ elevation = compression_filter(elevation);
+ elevation = three_halves_filter(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = small_Kernel_Sharpen(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = three_halves_filter(elevation);
+ elevation = small_Kernel_Smooth(elevation);
+ elevation = small_Kernel_Sharpen(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = smooth_Terrain_Further(elevation);
+ elevation = land_exponential_filter(elevation);
+ elevation = land_exponential_filter(elevation);
+ elevation = land_exponential_filter(elevation);
+ elevation = land_exponential_filter(elevation);
+
+ mountain_parsed = new int[DIMENSION][DIMENSION];
+ ocean_parsed = new int[DIMENSION][DIMENSION];
+ continent_Number = new int[DIMENSION][DIMENSION];
+
+ mountain_parsed = parse_Mountainscapes(elevation);
+
+ ocean_parsed = parse_Oceans(elevation);
+
+ wind_field = map_Wind_Field();
+
+ precipitation_Chart = calculate_Rain_Shadows(elevation,ocean_parsed,wind_field);
+
+ temperature_Chart = generate_Temperature_Chart();
+
+ climate_category = infer_Climate_Category();
+
+ determine_Continents();
+
+ fill_Continents();
+
+ float[][] modelInput = interpolateIntegerElevations(elevation);
+
+ modelInput = applyRandomizationFilter(modelInput);
+
+ chunkRandomizer = getChunkRandomizer(modelInput, DIMENSION);
+
+ rVal = new TerrainModel(DIMENSION,modelInput,chunkRandomizer,dynamicInterpRatio);
+
+ return rVal;
+ }
+
+ public long[][] getChunkRandomizer(float[][] elevationMap, int DIMENSION){
+ long[][] rVal = new long[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ long seed = (long)elevationMap[x][y];
+ if(x - 1 > 0){
+ seed = seed + (long)elevationMap[x-1][y];
+ if(y - 1 > 0){
+ seed = seed + (long)elevationMap[x-1][y-1];
+ }
+ if(y + 1 < DIMENSION){
+ seed = seed + (long)elevationMap[x-1][y+1];
+ }
+ }
+ if(x + 1 < DIMENSION){
+ seed = seed + (long)elevationMap[x+1][y];
+ if(y - 1 > 0){
+ seed = seed + (long)elevationMap[x+1][y-1];
+ }
+ if(y + 1 < DIMENSION){
+ seed = seed + (long)elevationMap[x+1][y+1];
+ }
+ }
+ if(y - 1 > 0){
+ seed = seed + (long)elevationMap[x][y-1];
+ }
+ if(y + 1 < DIMENSION){
+ seed = seed + (long)elevationMap[x][y+1];
+ }
+ rVal[x][y] = seed;
+ }
+ }
+ return rVal;
+ }
+
+ static float[][] applyRandomizationFilter(float[][] elevation){
+ float[][] rVal = new float[elevation.length][elevation[0].length];
+ for(int x = 0; x < DIMENSION-1; x++){
+ for(int y = 0; y < DIMENSION-1; y++){
+ rVal[x][y] = elevation[x][y] + Utilities.random_Integer(0, (int)(elevation[x][y] / 4));
+ }
+ }
+ return rVal;
+ }
+
+ static float[][] interpolateIntegerElevations(int[][] elevation){
+ int interpRatio = interpolationRatio;
+ float[][] rVal = new float[DIMENSION * interpRatio][DIMENSION * interpRatio];
+ for(int x = 0; x < DIMENSION-1; x++){
+ for(int y = 0; y < DIMENSION-1; y++){
+ for(int i = 0; i < interpRatio; i++){
+ for(int j = 0; j < interpRatio; j++){
+ float ratio1 = (i*j) * 1.0f / (interpRatio*interpRatio);
+ float ratio2 = ((interpRatio-i)*j) * 1.0f / (interpRatio*interpRatio);
+ float ratio3 = (i*(interpRatio-j)) * 1.0f / (interpRatio*interpRatio);
+ float ratio4 = ((interpRatio-i)*(interpRatio-j)) * 1.0f / (interpRatio*interpRatio);
+ rVal[x*interpRatio+interpRatio-i][y*interpRatio+interpRatio-j] =
+ (elevation[x ][y ] * ratio1 +
+ elevation[x+1][y ] * ratio2 +
+ elevation[x ][y+1] * ratio3 +
+ elevation[x+1][y+1] * ratio4) *
+ verticalInterpolationRatio
+ ;
+ }
+ }
+ }
+ }
+ DIMENSION = DIMENSION * interpRatio;
+ return rVal;
+ }
+
+ public static void anchor_To_Real_Region(){
+ //current_Region_X
+ //continents
+ //current_Continent
+ Continent target_continent = continents.get(current_Continent);
+ for(int x = 0; x < target_continent.dim_x; x++){
+ for(int y = 0; y < target_continent.dim_y; y++){
+ if(target_continent.regions[x][y]!=null){
+ current_Region_X = x;
+ current_Region_Y = y;
+ x = target_continent.dim_x;
+ y = target_continent.dim_y;
+ } else {
+
+ }
+ }
+ }
+ }
+
+ static int[][] simulate_Drainage(int[][] water_level, int[][] elevation, int dim_x, int dim_y){
+ int[][] rVal = new int[dim_x][dim_y];
+ for(int x = 0; x < dim_x; x++){
+ for(int y = 0; y < dim_y; y++){
+ rVal[x][y] = 0;
+ }
+ }
+ int kernel_offset_x[] = {
+ -1,0,0,1
+ };
+ int kernel_offset_y[] = {
+ 0,-1,1,0
+ };
+ int offset_kernel_size = 4;
+ for(int x = 0; x < dim_x; x++){
+ for(int y = 0; y < dim_y; y++){
+ int num_Water_Particles = water_level[x][y];
+ int elevation_Center = elevation[x][y];
+ int attractor_Values[] = new int[offset_kernel_size];
+ for(int j = 0; j < offset_kernel_size; j++) {
+ if(x + kernel_offset_x[j] >= 0 && x + kernel_offset_x[j] < dim_x && y + kernel_offset_y[j] >= 0 && y + kernel_offset_y[j] < dim_y) {
+ if(elevation[x+kernel_offset_x[j]][y+kernel_offset_y[j]] < elevation[x][y]){
+ attractor_Values[j] = (int)((elevation[x][y]-elevation[x+kernel_offset_x[j]][y+kernel_offset_y[j]])*1.0*water_level[x+kernel_offset_x[j]][y+kernel_offset_y[j]]);
+ } else {
+ attractor_Values[j] = 0;
+ }
+ }
+ }
+ int rand_num = 0;
+ int rand_Space = 0;
+ for(int j = 0; j < offset_kernel_size; j++){
+ rand_Space = rand_Space + attractor_Values[j];
+ }
+ rand_Space = rand_Space + water_level[x][y]; // account for water not moving downwards
+ int rand_Incrementer = 0;
+ boolean done = false;
+ for(int i = 0; i < num_Water_Particles; i++){
+ done = false;
+ rand_Incrementer = 0;
+ rand_num = Utilities.random_Integer(0, rand_Space);
+ for(int j = 0; j < offset_kernel_size; j++){
+ rand_Incrementer = rand_Incrementer + attractor_Values[j];
+ if(rand_num < rand_Incrementer){
+ if(attractor_Values[j] > 0){
+ if(rVal[x+kernel_offset_x[j]][y+kernel_offset_y[j]] < 400){
+ rVal[x+kernel_offset_x[j]][y+kernel_offset_y[j]]++;
+ }
+ done = true;
+ }
+ }
+ }
+ if(!done){
+ rVal[x][y]++;
+ }
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int sum_Array(int[][] arr, int dim_x, int dim_y){
+ int sum = 0;
+ for(int x = 0; x < dim_x; x++){
+ for(int y = 0; y < dim_y; y++){
+ sum = sum + arr[x][y];
+ }
+ }
+ return sum;
+ }
+
+ static void generate_Region_Elevation_Maps(Continent c){
+ int neighbor_offset_x[] = {
+ 1,0,-1,1,-1,1,0,-1
+ };
+ int neighbor_offset_y[] = {
+ 1,1,1,0,0,-1,-1,-1
+ };
+ //generate neighbor links
+ for(int x = 0; x < c.dim_x; x++){
+ for(int y = 0; y < c.dim_y; y++){
+ if(c.regions[x][y]!=null){
+ for(int i = 0; i < 8; i++){
+ if(x + neighbor_offset_x[i] >= 0 && x + neighbor_offset_x[i] < c.dim_x && y + neighbor_offset_y[i] >= 0 && y + neighbor_offset_y[i] < c.dim_y){
+ //+1 comes from getting the center of the kernel
+ //ie kernel is 3x3 therefore the center position is at 1,1 array-wise
+ c.regions[x][y].neighbors[neighbor_offset_x[i]+1][neighbor_offset_y[i]+1] = c.regions[x + neighbor_offset_x[i]][y + neighbor_offset_y[i]];
+ } else {
+ c.regions[x][y].neighbors[neighbor_offset_x[i]+1][neighbor_offset_y[i]+1] = null;
+ }
+ }
+ }
+ }
+ }
+ int region_Dim = Region.REGION_DIMENSION;
+ //set elevation goals
+ for(int x = 0; x < c.dim_x; x++){
+ for(int y = 0; y < c.dim_y; y++){
+ if(c.regions[x][y]!=null){
+ c.regions[x][y].elevation_Goal = c.elevation[x][y];
+ }
+ }
+ }
+ //interpolate base elevation values
+ int interpolation_kernel_offset_x[] = {0,1,0,1};
+ int interpolation_kernel_offset_y[] = {0,0,1,1};
+ int interpolation_kernel_size = 4;
+ int corner_Vals[][] = new int[2][2];
+ for(int x = 0; x < c.dim_x; x++){
+ for(int y = 0; y < c.dim_y; y++){
+ if (c.regions[x][y] != null) {
+ c.regions[x][y].chart_Elevation = new int[Region.REGION_DIMENSION][Region.REGION_DIMENSION];
+ //first the north-west corner
+ for(int i = 0; i < interpolation_kernel_size; i++){
+ if(x-1+interpolation_kernel_offset_x[i] >= 0 && x-1+interpolation_kernel_offset_x[i] < c.dim_x &&
+ y-1+interpolation_kernel_offset_y[i] >= 0 && y-1+interpolation_kernel_offset_y[i] < c.dim_y){
+ if(c.regions[x-1+interpolation_kernel_offset_x[i]][y-1+interpolation_kernel_offset_y[i]]!=null){
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] =
+ c.regions[x-1+interpolation_kernel_offset_x[i]][y-1+interpolation_kernel_offset_y[i]].elevation_Goal;
+ } else {
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] = 0;
+ }
+ }
+ }
+ int midpoint = (int)(Region.REGION_DIMENSION/2.0);
+ int sum = 0;
+ for(int i = 0; i < midpoint; i++){
+ for(int j = 0; j < midpoint; j++){
+ sum = 0;
+ sum = sum + (midpoint-i)*(midpoint-j)*corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[0]];
+ sum = sum + (i)*(midpoint-j)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[0]];
+ sum = sum + (midpoint-i)*(j)* corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[1]];
+ sum = sum + (i)*(j)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[1]];
+ c.regions[x][y].chart_Elevation[i][j] = sum;
+ }
+ }
+ //now the north-east corner
+ for(int i = 0; i < interpolation_kernel_size; i++){
+ if(x+interpolation_kernel_offset_x[i] >= 0 && x+interpolation_kernel_offset_x[i] < c.dim_x &&
+ y-1+interpolation_kernel_offset_y[i] >= 0 && y-1+interpolation_kernel_offset_y[i] < c.dim_y){
+ if(c.regions[x+interpolation_kernel_offset_x[i]][y-1+interpolation_kernel_offset_y[i]]!=null){
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] =
+ c.regions[x+interpolation_kernel_offset_x[i]][y-1+interpolation_kernel_offset_y[i]].elevation_Goal;
+ } else {
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] = 0;
+ }
+ }
+ }
+ for(int i = midpoint; i < Region.REGION_DIMENSION; i++){
+ for(int j = 0; j < midpoint; j++){
+ sum = 0;
+ sum = sum + (Region.REGION_DIMENSION-i)*(midpoint-j)*corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[0]];
+ sum = sum + (i-midpoint)*(midpoint-j)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[0]];
+ sum = sum + (Region.REGION_DIMENSION-i)*(j)* corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[1]];
+ sum = sum + (i-midpoint)*(j)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[1]];
+ c.regions[x][y].chart_Elevation[i][j] = sum;
+ }
+ }
+ //now the south-west corner
+ for(int i = 0; i < interpolation_kernel_size; i++){
+ if(x-1+interpolation_kernel_offset_x[i] >= 0 && x-1+interpolation_kernel_offset_x[i] < c.dim_x &&
+ y+interpolation_kernel_offset_y[i] >= 0 && y+interpolation_kernel_offset_y[i] < c.dim_y){
+ if(c.regions[x-1+interpolation_kernel_offset_x[i]][y+interpolation_kernel_offset_y[i]]!=null){
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] =
+ c.regions[x-1+interpolation_kernel_offset_x[i]][y+interpolation_kernel_offset_y[i]].elevation_Goal;
+ } else {
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] = 0;
+ }
+ }
+ }
+ for(int i = 0; i < midpoint; i++){
+ for(int j = midpoint; j < Region.REGION_DIMENSION; j++){
+ sum = 0;
+ sum = sum + (midpoint-i)*(Region.REGION_DIMENSION-j)*corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[0]];
+ sum = sum + (i)*(Region.REGION_DIMENSION-j)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[0]];
+ sum = sum + (midpoint-i)*(j-midpoint)* corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[1]];
+ sum = sum + (i)*(j-midpoint)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[1]];
+ c.regions[x][y].chart_Elevation[i][j] = sum;
+ }
+ }
+ //now the south-east corner
+ for(int i = 0; i < interpolation_kernel_size; i++){
+ if(x+interpolation_kernel_offset_x[i] >= 0 && x+interpolation_kernel_offset_x[i] < c.dim_x &&
+ y+interpolation_kernel_offset_y[i] >= 0 && y+interpolation_kernel_offset_y[i] < c.dim_y){
+ if(c.regions[x+interpolation_kernel_offset_x[i]][y+interpolation_kernel_offset_y[i]]!=null){
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] =
+ c.regions[x+interpolation_kernel_offset_x[i]][y+interpolation_kernel_offset_y[i]].elevation_Goal;
+ } else {
+ corner_Vals[interpolation_kernel_offset_x[i]][interpolation_kernel_offset_y[i]] = 0;
+ }
+ }
+ }
+ for(int i = midpoint; i < Region.REGION_DIMENSION; i++){
+ for(int j = midpoint; j < Region.REGION_DIMENSION; j++){
+ sum = 0;
+ sum = sum + (Region.REGION_DIMENSION-i)*(Region.REGION_DIMENSION-j)*corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[0]];
+ sum = sum + (i-midpoint)*(Region.REGION_DIMENSION-j)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[0]];
+ sum = sum + (Region.REGION_DIMENSION-i)*(j-midpoint)* corner_Vals[interpolation_kernel_offset_x[0]][interpolation_kernel_offset_y[1]];
+ sum = sum + (i-midpoint)*(j-midpoint)* corner_Vals[interpolation_kernel_offset_x[1]][interpolation_kernel_offset_y[1]];
+ c.regions[x][y].chart_Elevation[i][j] = sum;
+
+ }
+ }
+ }
+ }
+ }
+ Region region_Current = null;
+ for(int x = 0; x < c.dim_x; x++){
+ for(int y = 0; y < c.dim_y; y++){
+ if(c.regions[x][y]!=null){
+ if(region_Current == null){
+ region_Current = c.regions[x][y];
+ } else if(c.regions[x][y].elevation_Goal > region_Current.elevation_Goal){
+ region_Current = c.regions[x][y];
+ }
+ }
+ }
+ }
+ //drainage simulation
+ //operates on an open set
+ int adjacency_array_x[] = {
+ 1,0,1,2
+ };
+ int adjacency_array_y[] = {
+ 0,1,2,1
+ };
+ boolean simulate_Drainage = true;
+ ArrayList open_Set = new ArrayList();
+ open_Set.add(region_Current);
+ if(simulate_Drainage){
+ while(!open_Set.isEmpty()){
+ region_Current.chart_Drainage = new int[region_Dim][region_Dim];
+ for(int x = 0; x < region_Dim; x++){
+ for(int y = 0; y < region_Dim; y++){
+ region_Current.chart_Drainage[x][y] = 1;
+ }
+ }
+ if (region_Current.neighbors[1][0] != null) {
+ if (region_Current.neighbors[1][0].finished_Drainage_Simulation == true) {
+ for(int x = 0; x < region_Dim; x++){
+ region_Current.chart_Drainage[x][0] = 1 + region_Current.neighbors[1][0].chart_Drainage[x][region_Dim-1];
+ }
+ }
+ }
+ if (region_Current.neighbors[0][1] != null) {
+ if (region_Current.neighbors[0][1].finished_Drainage_Simulation == true) {
+ for(int x = 0; x < region_Dim; x++){
+ region_Current.chart_Drainage[0][x] = 1 + region_Current.neighbors[0][1].chart_Drainage[region_Dim-1][x];
+ }
+ }
+ }
+ if (region_Current.neighbors[1][2] != null) {
+ if (region_Current.neighbors[1][2].finished_Drainage_Simulation == true) {
+ for(int x = 0; x < region_Dim; x++){
+ region_Current.chart_Drainage[x][region_Dim-1] = 1 + region_Current.neighbors[1][2].chart_Drainage[x][0];
+ }
+ }
+ }
+ if (region_Current.neighbors[2][1] != null) {
+ if (region_Current.neighbors[2][1].finished_Drainage_Simulation == true) {
+ for(int x = 0; x < region_Dim; x++){
+ region_Current.chart_Drainage[region_Dim-1][x] = 1 + region_Current.neighbors[2][1].chart_Drainage[0][x];
+ }
+ }
+ }
+ region_Current.chart_Max_Water_Flow = new int[region_Dim][region_Dim];
+// while(sum_Array(region_Current.chart_Drainage,region_Dim,region_Dim)>0){
+// region_Current.chart_Drainage = simulate_Drainage(region_Current.chart_Drainage,region_Current.chart_Elevation,Region.REGION_DIMENSION,Region.REGION_DIMENSION);
+// for(int x = 0; x < region_Dim; x++){
+// for(int y = 0; y < region_Dim; y++){
+// if(region_Current.chart_Drainage[x][y] > region_Current.chart_Max_Water_Flow[x][y]){
+// region_Current.chart_Max_Water_Flow[x][y] = region_Current.chart_Drainage[x][y];
+// }
+// }
+// }
+// }
+ region_Current.chart_Drainage = region_Current.chart_Max_Water_Flow;
+ open_Set.remove(region_Current);
+ //TODO: When adding regions to the set, check if _their_ neighbors are higher elevation recursively (probably going to need its own function)
+ for (int i = 0; i < 4; i++) {
+ if (region_Current.neighbors[adjacency_array_x[i]][adjacency_array_y[i]] != null) {
+ if (region_Current.neighbors[adjacency_array_x[i]][adjacency_array_y[i]].finished_Drainage_Simulation == false) {
+ int next_height = region_Current.neighbors[adjacency_array_x[i]][adjacency_array_y[i]].elevation_Goal;
+ int index_to_insert_at = 0;
+ Iterator region_Iterator = open_Set.iterator();
+ while (region_Iterator.hasNext()) {
+ Region next = region_Iterator.next();
+ if (next.elevation_Goal > next_height) {
+ index_to_insert_at++;
+ } else {
+ break;
+ }
+ }
+ if(!open_Set.contains(region_Current.neighbors[adjacency_array_x[i]][adjacency_array_y[i]])){
+ open_Set.add(index_to_insert_at, region_Current.neighbors[adjacency_array_x[i]][adjacency_array_y[i]]);
+ }
+ }
+ }
+ }
+ region_Current.finished_Drainage_Simulation = true;
+ if(open_Set.size() > 0){
+ region_Current = open_Set.get(0);
+ }
+ }
+ }
+ }
+
+ static void create_Frame(){
+ frame.setBounds(25, 25, 300 + DIMENSION, 300 + DIMENSION);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.add(graphics);
+ frame.setVisible(true);
+ frame.addKeyListener(new KeyListener(){
+ public void keyTyped(KeyEvent ke) {
+ }
+
+ @Override
+ public void keyPressed(KeyEvent ke) {
+ if(ke.getKeyCode() == KeyEvent.VK_C){
+ increment_Current_Continent();
+ } else if(ke.getKeyCode() == KeyEvent.VK_V){
+ increment_Display_Toggle();
+ }
+ }
+
+ @Override
+ public void keyReleased(KeyEvent ke) {
+ }
+ }
+ );
+ }
+
+ static void fill_Continents(){
+ for(int i = 1; i < num_Continents + 1; i++){
+ Continent current = new Continent();
+ continents.add(current);
+ //find dimensions
+ int min_x = -1;
+ int min_y = -1;
+ int max_x = -1;
+ int max_y = -1;
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(continent_Number[x][y] == i){
+ if(min_x == -1){
+ min_x = x;
+ min_y = y;
+ max_x = x;
+ max_y = y;
+ } else {
+ if (x < min_x) {
+ min_x = x;
+ }
+ if (x > max_x) {
+ max_x = x;
+ }
+ if (y < min_y) {
+ min_y = y;
+ }
+ if (y > max_y) {
+ max_y = y;
+ }
+ }
+ }
+ }
+ }
+ int dim_x = max_x - min_x + 1;
+ int dim_y = max_y - min_y + 1;
+ current.dim_x = dim_x;
+ current.dim_y = dim_y;
+ current.chart_Climate = new int[dim_x][dim_y];
+ current.chart_Precipitation = new int[dim_x][dim_y];
+ current.chart_Temperature = new int[dim_x][dim_y];
+ current.chart_Wind_Macro = new int[dim_x][dim_y];
+ current.elevation = new int[dim_x][dim_y];
+ //zero out arrays
+ for(int x = 0; x < dim_x; x++){
+ for(int y = 0; y < dim_y; y++){
+ current.elevation[x][y] = 0;
+ current.chart_Climate[x][y] = 0;
+ current.chart_Precipitation[x][y] = 0;
+ current.chart_Temperature[x][y] = 50;
+ current.chart_Wind_Macro[x][y] = 0;
+ }
+ }
+ //fill continent level arrays
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(continent_Number[x][y] == i){
+ current.size++;
+ current.elevation[x-min_x][y-min_y] = elevation[x][y];
+ current.chart_Climate[x-min_x][y-min_y] = climate_category[x][y];
+ current.chart_Precipitation[x-min_x][y-min_y] = precipitation_Chart[x][y];
+ current.chart_Temperature[x-min_x][y-min_y] = temperature_Chart[x][y];
+ current.chart_Wind_Macro[x-min_x][y-min_y] = wind_field[x][y].x;
+ }
+ }
+ }
+ //create regions
+ current.regions = new Region[dim_x][dim_y];
+ for(int x = 0; x < dim_x; x++){
+ for(int y = 0; y < dim_y; y++){
+ if(continent_Number[x+min_x][y+min_y] == i){
+ current.regions[x][y] = new Region();
+ current.regions[x][y].elevation_Goal = current.elevation[x][y];
+ } else {
+ current.regions[x][y] = null;
+ }
+ }
+ }
+ generate_Region_Elevation_Maps(current);
+ }
+ }
+
+ static void floodfill_Continent_Number(int x, int y, int number){
+ continent_Number[x][y] = number;
+ int offset_X[] = {0,-1,0,1};
+ int offset_Y[] = {1,0,-1,0};
+ for(int i = 0; i < 4; i++){
+ if(x + offset_X[i] >= 0 && x + offset_Y[i] < DIMENSION){
+ if(y + offset_Y[i] >= 0 && y + offset_Y[i] < DIMENSION){
+ if(ocean_parsed[x + offset_X[i]][y + offset_Y[i]] < 25){
+ if(continent_Number[x + offset_X[i]][y + offset_Y[i]] == 0){
+ floodfill_Continent_Number(x + offset_X[i], y + offset_Y[i], number);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static void determine_Continents(){
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(ocean_parsed[x][y] < 25){
+ if(continent_Number[x][y] == 0){
+ num_Continents++;
+ floodfill_Continent_Number(x,y,num_Continents);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ 0 - ocean
+ 1 - tropical
+ 2 - subtropical
+ 3 - temperate
+ 4 - dry
+ 5 - polar
+ 6 - mountainous
+ */
+ static int[][] infer_Climate_Category(){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++) {
+ if (elevation[x][y] > ocean_Threshold) {
+ if (elevation[x][y] > mountain_Threshold) {
+ rVal[x][y] = 6;
+ } else {
+ if (precipitation_Chart[x][y] > 0) {
+ if (temperature_Chart[x][y] > 94) {
+ rVal[x][y] = 1;
+ } else if (temperature_Chart[x][y] > 80) {
+ rVal[x][y] = 2;
+ } else if (temperature_Chart[x][y] > 40) {
+ rVal[x][y] = 3;
+ } else {
+ rVal[x][y] = 5;
+ }
+ } else {
+ if (temperature_Chart[x][y] > 75) {
+ rVal[x][y] = 4;
+ } else if (temperature_Chart[x][y] > 40) {
+ rVal[x][y] = 4;
+ } else if (temperature_Chart[x][y] > 25) {
+ rVal[x][y] = 5;
+ } else {
+ rVal[x][y] = 5;
+ }
+ }
+ }
+ } else {
+ if (temperature_Chart[x][y] > 75) {
+ rVal[x][y] = 0;
+ } else if (temperature_Chart[x][y] > 40) {
+ rVal[x][y] = 0;
+ } else if (temperature_Chart[x][y] > 25) {
+ rVal[x][y] = 0;
+ } else {
+ rVal[x][y] = 5;
+ }
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] generate_Temperature_Chart(){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ int temp = 0;
+ for(int x = 0; x < DIMENSION; x++){
+ temp = (int)(100 - (Math.abs(x - DIMENSION/2.0) / (DIMENSION/2.0) * 100.0));
+ temp = (int)(Math.sin(temp/100.0 * Math.PI / 2.0) * 100.0);
+ for(int y = 0; y < DIMENSION; y++){
+ rVal[y][x] = temp;
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] calculate_Rain_Shadows(int[][] elevation_raws, int[][] ocean_parsed, Vector[][] wind_field){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ int rain_Particles[][] = new int[DIMENSION][DIMENSION];
+ int num_rain_particles = 0;
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(ocean_parsed[x][y] > 1){
+ rain_Particles[x][y] = 1;
+ rVal[x][y] = 1;
+ num_rain_particles++;
+ }
+ }
+ }
+ while(num_rain_particles > DIMENSION * 2) {
+ for (int x = 0; x < DIMENSION; x++) {
+ for (int y = 0; y < DIMENSION; y++) {
+ if (rain_Particles[x][y] >= 1) {
+ if (wind_field[x][y].x == -1) {
+ if (x > 0) {
+ if (elevation_raws[x - 1][y] < rain_Shadow_Blocker_Height) {
+ rain_Particles[x - 1][y] = 1;
+ rVal[x - 1][y] = 1;
+ } else {
+ }
+ if (wind_field[x][y].y == -1) {
+ if (y > 0) {
+ if (elevation_raws[x - 1][y - 1] < rain_Shadow_Blocker_Height) {
+ rain_Particles[x - 1][y - 1] = 1;
+ rVal[x - 1][y - 1] = 1;
+ }
+ }
+ } else if (wind_field[x][y].y == 1) {
+ if (y < DIMENSION - 1) {
+ if (elevation_raws[x - 1][y + 1] < rain_Shadow_Blocker_Height) {
+ rain_Particles[x - 1][y + 1] = 1;
+ rVal[x - 1][y + 1] = 1;
+ }
+ }
+ }
+ } else {
+ }
+ } else {
+ if (x < DIMENSION - 1) {
+ if (elevation_raws[x + 1][y] < rain_Shadow_Blocker_Height) {
+ rain_Particles[x + 1][y] = 1;
+ rVal[x + 1][y] = 1;
+ } else {
+ }
+ if (wind_field[x][y].y == -1) {
+ if (y > 0) {
+ if (elevation_raws[x + 1][y - 1] < rain_Shadow_Blocker_Height) {
+ rain_Particles[x + 1][y - 1] = 1;
+ rVal[x + 1][y - 1] = 1;
+ }
+ }
+ } else if (wind_field[x][y].y == 1) {
+ if (y < DIMENSION - 1) {
+ if (elevation_raws[x + 1][y + 1] < rain_Shadow_Blocker_Height) {
+ rain_Particles[x + 1][y + 1] = 1;
+ rVal[x + 1][y + 1] = 1;
+ }
+ }
+ }
+ } else {
+ }
+ }
+ rain_Particles[x][y] = 0;
+ }
+ }
+ }
+ num_rain_particles = 0;
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(rain_Particles[x][y] == 1){
+ num_rain_particles++;
+ }
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static Vector[][] map_Wind_Field(){
+ Vector rVal[][] = new Vector[DIMENSION][DIMENSION];
+ int sixth = (int)(DIMENSION / 6.0);
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(x < sixth){
+ rVal[x][y] = new Vector();
+ rVal[x][y].x = -1;
+ rVal[x][y].y = -1;
+ } else if(x < sixth * 2){
+ rVal[x][y] = new Vector();
+ rVal[x][y].x = 1;
+ rVal[x][y].y = 1;
+ } else if(x < sixth * 3){
+ rVal[x][y] = new Vector();
+ rVal[x][y].x = -1;
+ rVal[x][y].y = -1;
+ } else if(x < sixth * 4){
+ rVal[x][y] = new Vector();
+ rVal[x][y].x = -1;
+ rVal[x][y].y = 1;
+ } else if(x < sixth * 5){
+ rVal[x][y] = new Vector();
+ rVal[x][y].x = 1;
+ rVal[x][y].y = -1;
+ } else {
+ rVal[x][y] = new Vector();
+ rVal[x][y].x = -1;
+ rVal[x][y].y = 1;
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] parse_Oceans(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(data[x][y] < ocean_Threshold){
+ rVal[x][y] = ocean_Threshold;
+ } else {
+ rVal[x][y] = 0;
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] parse_Mountainscapes(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(data[x][y] > mountain_Threshold){
+ rVal[x][y] = mountain_Threshold;
+ } else {
+ rVal[x][y] = 0;
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] closed_Set;
+
+ static int floodfill_Reach_Threshold(int[][] data, int[][] closed_Set, int x, int y, int min_val, int max_val){
+ int rVal = 0;
+ int num_hits;
+ int offset_X[] = {-1,-1,-1,0,0,0,1,1,1};
+ int offset_Y[] = {-1,0,1,-1,0,1,-1,0,1};
+ if(data[x][y] > min_val && data[x][y] < max_val){
+ closed_Set[x][y] = 1;
+ for(int i = 0; i < 9; i++){
+ if(x + offset_X[i] >= 0 &&
+ x + offset_X[i] < DIMENSION &&
+ y + offset_Y[i] >= 0 &&
+ y + offset_Y[i] < DIMENSION){
+ if(closed_Set[x + offset_X[i]][y+offset_Y[i]] == 0){
+ rVal = rVal + floodfill_Reach_Threshold(data,closed_Set,x + offset_X[i],y + offset_Y[i], min_val, max_val);
+ }
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] remove_Small_Mountain_Ranged(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ boolean removed_Something = false;
+// for (int x = 0; x < DIMENSION; x++) {
+// for (int y = 0; y < DIMENSION; y++) {
+// rVal[x][y] = data[x][y];
+// }
+// }
+// while (true) {
+ for (int x = 0; x < DIMENSION; x++) {
+ for (int y = 0; y < DIMENSION; y++) {
+ rVal[x][y] = data[x][y];
+ if (data[x][y] > mountain_Threshold) {
+ rVal[x][y] = rVal[x][y] - 5;
+// closed_Set = new int[DIMENSION][DIMENSION];
+// if (floodfill_Reach_Threshold(rVal, closed_Set, x, y, mountain_Threshold, 101) < mountain_Range_Size_Minimum) {
+// rVal[x][y] = rVal[x][y] - 25;
+//// removed_Something = true;
+// }
+ }
+ }
+ }
+// if(!removed_Something){
+// break;
+//// } else {
+// removed_Something = false;
+// }
+// }
+ return rVal;
+ }
+
+ static int[][] compression_filter(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(data[x][y] < 25){
+ rVal[x][y] = (int)(data[x][y] * 3.0 / 2.0);
+ } else if(data[x][y] > 75){
+ rVal[x][y] = (int)(data[x][y] / 3.0 * 2.0);
+ } else {
+ rVal[x][y] = data[x][y];
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] three_halves_filter(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ rVal[x][y] = (int)(data[x][y] * 3.0 / 2.0);
+ if(rVal[x][y] > 100){
+ rVal[x][y] = 100;
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] two_third_filter(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ rVal[x][y] = (int)(data[x][y] * 2.0 / 3.0);
+ if(rVal[x][y] < 0){
+ rVal[x][y] = 0;
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] high_end_two_third_filter(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++) {
+ if (data[x][y] > 50) {
+ rVal[x][y] = (int) (data[x][y] * 2.0 / 3.0);
+ if (rVal[x][y] < 0) {
+ rVal[x][y] = 0;
+ }
+ } else {
+ rVal[x][y] = data[x][y];
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] reduce_mid_high_end_filter(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++) {
+ if (data[x][y] > 50 && data[x][y] < 75) {
+ rVal[x][y] = (int) (data[x][y] * 2.0 / 3.0);
+ if (rVal[x][y] < 0) {
+ rVal[x][y] = 0;
+ }
+ } else {
+ rVal[x][y] = data[x][y];
+ }
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] small_Kernel_Smooth(int elevation_Map[][]){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ int kernel_offset_x[] = {
+ -1,0,1,
+ -1,0,1,
+ -1,0,1
+ };
+ int kernel_offset_y[] = {
+ -1,-1,-1,
+ 0,0,0,
+ 1,1,1
+ };
+ int kernle_modifier[] = {
+ 1,2,1,
+ 2,4,2,
+ 1,2,1
+ };
+ for(int x = 1; x < DIMENSION - 1; x++){
+ for(int y = 1; y < DIMENSION - 1; y++){
+ int sum = 0;
+ for(int i = 0; i < 9; i++){
+ sum = sum + elevation_Map[x+kernel_offset_x[i]][y+kernel_offset_y[i]] * kernle_modifier[i];
+ }
+ sum = (int)(sum/13.0);
+ if(sum > 100){
+ sum = 100;
+ }
+ rVal[x][y] = sum;
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] small_Kernel_Sharpen(int elevation_Map[][]){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ int kernel_offset_x[] = {
+ -1,0,1,
+ -1,0,1,
+ -1,0,1
+ };
+ int kernel_offset_y[] = {
+ -1,-1,-1,
+ 0,0,0,
+ 1,1,1
+ };
+ int kernel_modifier[] = {
+ 0,-1,0,
+ -1,5,-1,
+ 0,-1,0
+ };
+ for(int x = 1; x < DIMENSION - 1; x++){
+ for(int y = 1; y < DIMENSION - 1; y++){
+ int sum = 0;
+ for(int i = 0; i < 9; i++){
+ sum = sum + elevation_Map[x+kernel_offset_x[i]][y+kernel_offset_y[i]] * kernel_modifier[i];
+ }
+// sum = (int)(sum/13.0);
+ if(sum > 100){
+ sum = 100;
+ }
+ if(sum < 0){
+ sum = 0;
+ }
+ rVal[x][y] = sum;
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] smooth_Terrain_Further(int elevation_Map[][]){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ int kernel_offset_x[] = {-2,-1,0,1,2,
+ -2,-1,0,1,2,
+ -2,-1,0,1,2,
+ -2,-1,0,1,2,
+ -2,-1,0,1,2,
+ };
+ int kernel_offset_y[] = {-2,-2,-2,-2,-2,
+ -1,-1,-1,-1,-1,
+ 0,0,0,0,0,
+ 1,1,1,1,1,
+ 2,2,2,2,2};
+ int kernel_modifier[] = {
+ 1,4,6,4,1,
+ 4,16,24,16,4,
+ 6,24,36,24,6,
+ 4,16,24,16,4,
+ 1,4,6,4,1
+ };
+ for(int x = 2; x < DIMENSION - 2; x++){
+ for(int y = 2; y < DIMENSION - 2; y++){
+ int sum = 0;
+ for(int i = 0; i < 25; i++){
+ sum = sum + elevation_Map[x+kernel_offset_x[i]][y+kernel_offset_y[i]] * kernel_modifier[i];
+ }
+ sum = (int)(sum/256.0);
+ if(sum > 100){
+ sum = 100;
+ }
+ rVal[x][y] = sum;
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] land_exponential_filter(int[][] data){
+ int rVal[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(data[x][y] > TerrainGen.ocean_Threshold && data[x][y] < 90){
+
+// System.out.print((data[x][y] - ocean_Threshold) + "/" + (100.0 - ocean_Threshold) + "=" + ((data[x][y] - ocean_Threshold) / (100.0 - ocean_Threshold)) + " ");
+// System.out.print(data[x][y] + "->");
+ rVal[x][y] = (int)(data[x][y] * Math.exp(-(1.0 - ((data[x][y] - ocean_Threshold) / (100.0 - ocean_Threshold)))) * 0.2f + data[x][y] * 0.8f);
+ if(rVal[x][y] < TerrainGen.ocean_Threshold){
+ rVal[x][y] = TerrainGen.ocean_Threshold + 1;
+ }
+// System.out.println(rVal[x][y]);
+ if(Math.exp(-(1.0 - ((data[x][y] - ocean_Threshold) / (100.0 - ocean_Threshold)))) > 1.0){
+ System.out.println("WARNING!!");
+ }
+ } else {
+ rVal[x][y] = data[x][y];
+ }
+ }
+ }
+ return rVal;
+ }
+
+ int[][] generate_Interpolation(int[][] data){
+ /*
+ Looks at 3x3 kernel
+ */
+ int kernel_offset_x[] = {-1,0,1,-1,0,1,-1,0,1};
+ int kernel_offset_y[] = {1,1,1,0,0,0,-1,-1,-1};
+ int rVal[][] = new int[100][100];
+ return rVal;
+ }
+
+ static int[][] interpolate_Elevation_Raws(int[][] raw){
+ int rVal[][] = new int[DIMENSION * 2][DIMENSION * 2];
+ for(int x = 0; x < DIMENSION - 1; x++){
+ for(int y = 0; y < DIMENSION - 1; y++){
+ rVal[x*2][y*2] = raw[x][y];
+ rVal[x*2+1][y*2] = (raw[x][y] + raw[x+1][y])/2;
+ rVal[x*2][y*2+1] = (raw[x][y] + raw[x][y+1])/2;
+ rVal[x*2+1][y*2+1] = (raw[x][y] + raw[x+1][y+1])/2;
+ }
+ }
+ return rVal;
+ }
+
+ static int[][] get_Pregened_Data(){
+ int rVal[][] = {{0, 0, 0, 0, 0, 0, 0, 0, 2, 10, 11, 24, 19, 99, 99, 70, 39, 11, 10, 0, 0, 2, 8, 0, 0, 0, 0, 0, 28, 2, 9, 17, 30, 51, 58, 4, 57, 36, 13, 22, 13, 14, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 1, 12, 1, 15, 4, 57, 39, 6, 15, 23, 22, 5, 17, 3, 0, 10, 0, 10, 0, 0, 1, 3, 1, 9, 5, 12, 6, 13, 6, 38, 33, 78, 30, 36, 55, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 23, 47, 1, 27, 30, 12, 9, 2, 0, 5, 12, 0, 10, 0, 0, 3, 0, 3, 11, 32, 16, 1, 4, 21, 5, 3, 29, 6, 3, 11, 8, 26, 11, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 32, 34, 13, 26, 0, 99, 1, 29, 68, 13, 0, 3, 0, 0, 0, 0, 5, 23, 3, 4, 38, 13, 26, 0, 20, 3, 25, 16, 42, 6, 55, 19, 8, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 6, 6, 36, 21, 0, 48, 7, 40, 22, 25, 1, 16, 2, 0, 13, 5, 0, 0, 2, 6, 27, 20, 12, 19, 32, 30, 27, 29, 14, 1, 31, 46, 12, 50, 32, 21, 13, 16, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 31, 28, 19, 14, 17, 20, 7, 1, 1, 64, 4, 15, 4, 10, 32, 0, 0, 0, 1, 1, 3, 0, 16, 20, 9, 23, 7, 9, 20, 4, 0, 2, 6, 2, 18, 14, 13, 42, 0, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 15, 5, 26, 12, 27, 7, 19, 28, 4, 36, 39, 30, 28, 12, 12, 5, 0, 9, 18, 4, 6, 1, 29, 11, 12, 4, 1, 4, 22, 3, 10, 1, 0, 2, 1, 34, 1, 0, 10, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 2, 13, 16, 3, 19, 27, 0, 25, 69, 38, 21, 33, 44, 3, 1, 7, 11, 0, 6, 2, 20, 23, 6, 3, 8, 21, 15, 27, 5, 0, 5, 1, 45, 1, 19, 16, 40, 0, 0, 14, 11, 12, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 5, 23, 21, 35, 9, 39, 58, 28, 7, 21, 30, 33, 3, 7, 16, 11, 9, 14, 5, 19, 14, 16, 21, 41, 5, 14, 22, 13, 17, 20, 17, 6, 25, 18, 14, 23, 10, 15, 20, 3, 7, 4, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 7, 60, 13, 5, 35, 33, 7, 21, 35, 25, 28, 24, 3, 38, 17, 30, 3, 4, 21, 4, 21, 37, 24, 2, 0, 13, 22, 0, 3, 15, 2, 24, 0, 13, 27, 8, 34, 3, 11, 0, 18, 22, 24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 9, 0, 3, 5, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 4, 5, 1, 49, 26, 28, 11, 5, 4, 15, 17, 5, 34, 25, 40, 13, 35, 10, 81, 20, 15, 21, 21, 18, 19, 10, 0, 17, 5, 1, 10, 10, 20, 11, 15, 10, 30, 23, 45, 24, 30, 35, 21, 36, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 14, 27, 17, 10, 26, 12, 19, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 1, 0, 46, 12, 17, 0, 1, 24, 11, 10, 9, 3, 25, 45, 36, 45, 1, 52, 14, 0, 24, 24, 33, 37, 7, 22, 3, 2, 6, 18, 11, 0, 16, 5, 7, 19, 5, 0, 15, 39, 31, 4, 24, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 10, 41, 99, 1, 36, 32, 1, 11, 11, 33, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 2, 11, 6, 1, 0, 19, 14, 0, 0, 0, 34, 26, 63, 20, 46, 34, 9, 24, 37, 53, 25, 20, 2, 14, 2, 2, 0, 5, 8, 1, 21, 11, 3, 28, 2, 4, 36, 8, 34, 31, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 23, 43, 23, 24, 31, 62, 24, 2, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 25, 0, 0, 14, 20, 16, 0, 0, 0, 0, 35, 58, 60, 77, 29, 24, 44, 11, 0, 5, 1, 4, 0, 4, 3, 0, 0, 0, 2, 34, 12, 0, 52, 15, 22, 37, 2, 14, 26, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 32, 31, 10, 42, 32, 21, 29, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 2, 0, 0, 0, 0, 27, 47, 82, 33, 22, 28, 20, 22, 21, 7, 6, 1, 0, 0, 0, 2, 0, 0, 0, 10, 15, 9, 27, 0, 1, 0, 5, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 74, 19, 31, 0, 9, 4, 27, 22, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 58, 13, 13, 46, 47, 4, 47, 14, 35, 3, 5, 4, 18, 4, 0, 0, 0, 0, 1, 1, 10, 0, 4, 0, 0, 0, 8, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 89, 20, 13, 5, 4, 3, 5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 38, 30, 39, 18, 24, 8, 6, 4, 0, 0, 1, 1, 4, 1, 2, 1, 0, 0, 6, 6, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 31, 2, 45, 30, 72, 68, 9, 27, 2, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25, 6, 8, 2, 6, 15, 7, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 99, 21, 23, 0, 2, 33, 1, 22, 44, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 29, 4, 1, 1, 1, 4, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 13, 9, 31, 7, 29, 30, 23, 2, 36, 6, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 13, 4, 5, 2, 5, 2, 8, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 47, 39, 11, 16, 41, 40, 56, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 12, 13, 11, 13, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, 45, 16, 24, 14, 3, 27, 84, 23, 23, 11, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 5, 1, 4, 0, 1, 8, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30, 18, 9, 1, 22, 31, 57, 9, 46, 33, 19, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 4, 2, 1, 10, 8, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 9, 11, 14, 45, 46, 34, 31, 27, 43, 16, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 3, 0, 3, 1, 2, 7, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 2, 30, 23, 30, 7, 30, 14, 20, 49, 79, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 35, 10, 14, 33, 54, 30, 61, 38, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 22, 24, 46, 7, 30, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 5, 0, 0, 0, 5, 17, 20, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 2, 2, 3, 0, 13, 23, 11, 10, 14, 0, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 11, 1, 0, 27, 11, 10, 5, 21, 7, 14, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 41, 29, 9, 1, 8, 2, 12, 72, 16, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 6, 17, 4, 10, 25, 13, 15, 16, 12, 1, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 22, 10, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 21, 0, 0, 0, 1, 3, 45, 31, 1, 91, 73, 2, 50, 0, 19, 2, 3, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 2, 17, 15, 87, 9, 30, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 9, 17, 0, 0, 0, 0, 0, 36, 6, 19, 46, 8, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 34, 38, 48, 15, 39, 1, 2, 13, 5, 9, 35, 24, 36, 26, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35, 25, 23, 0, 0, 0, 0, 0, 0, 37, 27, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 28, 27, 54, 21, 3, 8, 36, 2, 0, 8, 18, 37, 11, 75, 20, 9, 5, 2, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 29, 27, 1, 0, 0, 0, 0, 0, 99, 92, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 17, 81, 40, 45, 15, 42, 33, 5, 37, 55, 28, 14, 8, 8, 4, 20, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 14, 12, 43, 71, 19, 27, 59, 23, 61, 31, 23, 28, 48, 12, 27, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 99, 97, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 16, 29, 12, 7, 57, 46, 21, 4, 15, 56, 6, 46, 54, 0, 17, 9, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 20, 40, 42, 35, 5, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 24, 8, 1, 48, 43, 20, 26, 8, 11, 7, 13, 25, 26, 23, 5, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 6, 25, 50, 99, 19, 0, 15, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 6, 11, 0, 3, 68, 3, 1, 32, 27, 23, 20, 6, 32, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 1, 27, 99, 87, 43, 50, 5, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 2, 24, 45, 45, 15, 23, 71, 16, 24, 2, 25, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 11, 0, 1, 20, 99, 6, 20, 27, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 3, 41, 36, 14, 16, 30, 46, 59, 58, 32, 29, 32, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 11, 12, 0, 17, 11, 99, 99, 59, 22, 19, 21, 3, 3, 11, 0, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 3, 99, 14, 6, 7, 37, 30, 8, 0, 37, 18, 2, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 9, 2, 2, 10, 11, 9, 31, 95, 99, 43, 5, 10, 12, 9, 7, 16, 24, 6, 1, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 8, 18, 26, 2, 19, 23, 28, 20, 78, 8, 1, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 12, 14, 9, 15, 12, 2, 28, 59, 41, 28, 4, 2, 8, 19, 1, 3, 4, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 8, 9, 2, 28, 20, 11, 31, 4, 26, 19, 18, 15, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 22, 12, 23, 7, 3, 6, 19, 78, 22, 10, 3, 5, 13, 21, 2, 10, 15, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 15, 1, 2, 9, 39, 14, 28, 27, 2, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 1, 9, 30, 15, 0, 4, 3, 17, 27, 2, 25, 40, 7, 13, 25, 6, 15, 8, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 5, 23, 0, 1, 47, 17, 8, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 15, 5, 4, 44, 10, 19, 2, 1, 0, 3, 9, 5, 9, 8, 13, 3, 21, 7, 19, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 3, 13, 23, 5, 7, 4, 17, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 21, 2, 0, 24, 2, 4, 4, 2, 16, 0, 1, 21, 10, 2, 2, 2, 0, 26, 11, 3, 6, 2, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 27, 12, 0, 33, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 2, 18, 13, 11, 18, 4, 3, 2, 0, 3, 11, 18, 9, 5, 10, 8, 5, 0, 0, 1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 5, 19, 8, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 3, 4, 0, 1, 5, 1, 5, 2, 0, 2, 2, 1, 3, 2, 4, 2, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 3, 18, 1, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 8, 1, 0, 0, 2, 5, 7, 3, 2, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 2, 0},
+{0, 0, 0, 0, 0, 0, 7, 1, 10, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 4, 2},
+{0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 5, 1, 3, 9, 0, 0, 0, 0, 0, 0, 0, 4, 2, 3, 1, 0, 1, 3, 0, 5},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 13, 2, 19, 10, 1, 0, 0, 0, 0, 1, 5, 7, 1, 3, 7, 1, 0, 5},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 10, 19, 14, 19, 11, 23, 16, 3, 6, 5, 0, 0, 0, 0, 1, 0, 0, 5, 1, 3, 1, 17, 2},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 15, 7, 6, 3, 10, 4, 21, 0, 3, 4, 10, 0, 0, 0, 2, 1, 0, 4, 2, 4, 7, 18},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 14, 3, 0, 11, 26, 2, 10, 20, 3, 12, 11, 30, 0, 0, 0, 0, 1, 1, 2, 0, 2, 1, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 33, 21, 7, 39, 29, 4, 13, 6, 4, 12, 7, 11, 0, 0, 0, 0, 0, 0, 1, 5, 1, 3, 0, 18, 26},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 16, 11, 11, 0, 18, 5, 4, 7, 7, 1, 14, 3, 0, 3, 1, 1, 1, 0, 0, 2, 1, 7, 4, 8, 11},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 1, 21, 27, 9, 12, 10, 4, 14, 3, 3, 0, 13, 5, 2, 3, 3, 5, 14, 3, 19, 0, 3, 2, 8, 12},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, 6, 2, 0, 4, 28, 4, 9, 20, 7, 23, 6, 0, 6, 7, 4, 4, 23, 8, 5, 7, 11, 9, 8, 5},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 1, 1, 6, 10, 51, 17, 32, 1, 11, 3, 5, 10, 0, 1, 6, 12, 0, 18, 8, 0, 0, 1, 14},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 5, 9, 16, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 20, 1, 7, 0, 22, 4, 8, 3, 23, 5, 27, 6, 1, 24, 2, 2, 11, 10, 10, 1, 0, 5},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 1, 1, 20, 9, 3, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 8, 1, 8, 17, 0, 9, 1, 11, 2, 14, 10, 6, 25, 0, 10, 5, 14, 2, 8, 0, 1, 6, 5, 1},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 0, 21, 7, 3, 0, 15, 11, 2, 25, 0, 1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 5, 10, 26, 31, 17, 8, 11, 18, 10, 5, 0, 2, 1, 14, 8, 32, 8, 12, 10, 12, 5, 0, 9, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 20, 2, 0, 0, 7, 13, 2, 0, 0, 15, 28, 9, 4, 19, 35, 10, 0, 12, 6, 5, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 6, 12, 0, 11, 0, 4, 15, 18, 24, 10, 11, 35, 3, 1, 4, 17, 13, 2, 6, 0, 11, 2, 2},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 0, 10, 7, 25, 11, 5, 6, 0, 0, 10, 8, 7, 41, 17, 14, 1, 10, 20, 11, 13, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 5, 19, 2, 1, 12, 21, 4, 7, 4, 3, 1, 19, 0, 0, 14, 9, 21, 0, 1, 15, 0, 1, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 9, 4, 9, 22, 10, 0, 46, 12, 3, 3, 2, 1, 0, 11, 5, 65, 7, 13, 14, 5, 5, 21, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10, 10, 0, 1, 6, 18, 1, 11, 3, 6, 24, 2, 1, 0, 24, 2, 4, 1, 1, 0, 3, 1},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 2, 7, 4, 18, 2, 0, 7, 11, 2, 5, 15, 20, 1, 6, 11, 6, 13, 3, 2, 17, 15, 6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 16, 7, 6, 22, 0, 7, 12, 16, 2, 10, 1, 7, 17, 3, 3, 12, 19, 2, 2, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 25, 15, 21, 4, 2, 0, 18, 1, 0, 2, 9, 9, 0, 3, 4, 27, 16, 38, 1, 11, 13, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 0, 9, 7, 12, 23, 0, 11, 32, 3, 20, 5, 2, 5, 1, 0, 5, 5, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 33, 11, 4, 4, 3, 1, 5, 5, 0, 0, 0, 2, 5, 5, 2, 10, 9, 15, 16, 28, 11, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 7, 1, 2, 0, 2, 9, 3, 2, 32, 30, 0, 3, 2, 3, 5, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 20, 23, 8, 22, 2, 3, 9, 3, 14, 6, 1, 0, 0, 0, 0, 0, 1, 2, 0, 48, 1, 26, 44, 1, 2, 8, 14, 6, 4, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 1, 10, 0, 0, 0, 0, 0, 1, 11, 3, 15, 7, 15, 11, 2, 9, 4, 4, 0, 7},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 6, 11, 6, 22, 9, 7, 5, 20, 18, 7, 1, 1, 1, 0, 0, 0, 2, 4, 10, 24, 1, 14, 14, 33, 8, 18, 4, 23, 32, 3, 2, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 28, 7, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 1, 5, 12, 0, 9, 51, 0, 12, 0, 0, 1, 4, 6, 13, 4, 1, 4, 8, 5, 6, 14, 18, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 1, 23, 2, 26, 8, 8, 0, 24, 12, 48, 2, 39, 1, 20, 0, 1, 0, 0, 7, 28, 14, 14, 2, 8, 40, 20, 9, 16, 25, 9, 9, 6, 6, 1, 11, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 4, 8, 4, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 8, 1, 6, 5, 0, 0, 5, 0, 0, 0, 4, 6, 26, 11, 16, 1, 22, 1, 14, 25, 0, 6, 3},
+{0, 0, 0, 0, 0, 0, 2, 5, 11, 11, 10, 2, 21, 2, 4, 20, 18, 2, 22, 0, 23, 26, 1, 17, 2, 1, 22, 0, 8, 2, 13, 56, 14, 22, 47, 99, 39, 4, 11, 5, 3, 14, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 11, 2, 9, 16, 9, 4, 0, 0, 0, 0, 0, 9, 2, 0, 7, 6, 14, 9, 39, 13, 2, 0, 7, 1, 15, 3, 5, 46, 9, 13, 4, 0, 0, 10, 1},
+{0, 0, 0, 0, 0, 0, 0, 14, 13, 8, 12, 0, 5, 1, 4, 23, 14, 33, 0, 67, 9, 15, 5, 7, 6, 1, 8, 17, 37, 25, 6, 23, 16, 33, 37, 15, 4, 36, 30, 9, 20, 4, 25, 9, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 10, 1, 0, 23, 12, 6, 22, 15, 9, 4, 6, 0, 2, 0, 0, 0, 4, 0, 0, 10, 8, 6, 25, 22, 9, 36, 0, 1, 5, 5, 18, 11, 15, 19, 0, 32, 7, 0, 3, 0},
+{0, 0, 0, 0, 2, 15, 2, 3, 5, 11, 27, 0, 23, 8, 28, 9, 8, 3, 8, 16, 13, 28, 20, 7, 20, 1, 23, 42, 16, 6, 25, 41, 29, 43, 58, 2, 26, 27, 13, 21, 22, 22, 46, 7, 15, 6, 18, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 6, 11, 12, 3, 19, 19, 28, 5, 4, 19, 0, 0, 0, 0, 0, 6, 8, 8, 1, 10, 3, 4, 12, 1, 7, 14, 9, 0, 15, 4, 1, 17, 5, 2, 11, 8, 8, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 5, 0, 41, 11, 27, 12, 1, 13, 13, 10, 16, 4, 2, 17, 6, 4, 1, 1, 2, 25, 24, 42, 10, 15, 0, 26, 26, 29, 18, 99, 1, 40, 38, 19, 2, 24, 8, 4, 25, 41, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 12, 0, 99, 13, 6, 5, 27, 3, 16, 4, 23, 5, 0, 0, 0, 6, 7, 8, 2, 13, 1, 28, 7, 5, 19, 14, 14, 0, 1, 27, 15, 3, 3, 2, 9, 7, 5, 1},
+{0, 0, 0, 0, 0, 0, 0, 0, 4, 21, 13, 7, 0, 6, 22, 4, 3, 10, 6, 40, 0, 6, 10, 40, 27, 17, 2, 1, 28, 0, 5, 28, 7, 10, 39, 6, 34, 52, 35, 8, 78, 6, 10, 41, 25, 33, 3, 36, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 4, 8, 32, 11, 15, 35, 30, 37, 19, 28, 30, 35, 14, 0, 0, 0, 10, 18, 4, 4, 54, 7, 21, 6, 6, 17, 5, 7, 0, 0, 1, 8, 7, 19, 8, 9, 0, 0, 0, 3},
+{0, 0, 0, 0, 0, 0, 3, 0, 21, 10, 4, 15, 22, 1, 1, 5, 8, 2, 29, 23, 21, 2, 30, 2, 1, 3, 13, 57, 5, 26, 5, 32, 44, 8, 22, 36, 46, 0, 10, 21, 10, 7, 10, 25, 3, 2, 14, 17, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 14, 12, 20, 8, 5, 1, 27, 0, 1, 19, 22, 25, 18, 2, 1, 16, 0, 2, 1, 0, 28, 2, 1, 1, 6, 15, 11, 0, 0, 0, 0, 12, 4, 10, 8, 3, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 10, 4, 22, 9, 2, 2, 6, 4, 8, 7, 7, 16, 16, 18, 11, 27, 32, 34, 49, 4, 99, 14, 4, 63, 34, 5, 32, 9, 3, 18, 48, 51, 12, 8, 41, 10, 7, 8, 30, 12, 1, 26, 26, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 12, 7, 11, 34, 3, 23, 18, 32, 5, 3, 36, 11, 6, 2, 0, 30, 29, 25, 0, 4, 4, 12, 3, 16, 6, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 7, 6, 19, 13, 6, 0, 1, 3, 1, 0, 3, 20, 4, 13, 0, 3, 6, 26, 1, 59, 42, 99, 21, 17, 26, 69, 5, 2, 47, 36, 88, 9, 6, 23, 47, 18, 11, 4, 25, 33, 32, 3, 41, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, 1, 8, 4, 12, 6, 30, 23, 1, 5, 18, 50, 19, 24, 8, 10, 8, 1, 6, 8, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 7, 0, 0, 0, 0, 0, 2, 1, 4, 8, 7, 1, 9, 40, 13, 68, 39, 18, 1, 27, 27, 23, 30, 13, 23, 12, 9, 20, 24, 68, 27, 45, 29, 34, 31, 22, 13, 4, 19, 8, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 0, 7, 3, 6, 0, 1, 11, 5, 10, 11, 22, 10, 25, 17, 8, 7, 1, 3, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 11, 1, 0, 0, 0, 0, 0, 0, 1, 6, 1, 13, 19, 2, 67, 99, 33, 7, 6, 1, 29, 46, 5, 17, 53, 5, 0, 41, 20, 17, 9, 52, 21, 19, 47, 19, 0, 26, 9, 0, 14, 1, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 21, 11, 3, 8, 2, 27, 53, 36, 20, 50, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 9, 9, 11, 10, 6, 3, 50, 99, 82, 21, 31, 27, 15, 8, 6, 6, 28, 3, 66, 7, 1, 22, 9, 76, 4, 13, 46, 50, 6, 20, 6, 2, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 13, 2, 15, 18, 7, 3, 8, 18, 3, 12, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 2, 6, 2, 1, 21, 42, 99, 47, 16, 47, 12, 14, 3, 26, 3, 37, 51, 18, 1, 5, 13, 4, 40, 26, 45, 28, 1, 47, 16, 8, 2, 2, 2, 0, 0, 3, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 39, 32, 25, 9, 22, 3, 7, 14, 75, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 6, 16, 11, 20, 13, 3, 68, 99, 20, 15, 10, 15, 0, 8, 15, 3, 3, 14, 27, 25, 27, 3, 0, 13, 12, 31, 8, 2, 18, 4, 13, 0, 0, 0, 5, 0, 2, 9, 0, 0, 1, 4, 1, 0, 0, 2, 3, 7, 2, 1, 11, 17, 2, 10, 11, 1, 32, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 5, 4, 3, 4, 7, 11, 9, 15, 43, 14, 17, 2, 18, 0, 12, 5, 26, 7, 11, 7, 42, 22, 19, 0, 5, 5, 5, 3, 9, 11, 0, 3, 0, 0, 2, 3, 17, 1, 3, 0, 0, 0, 11, 0, 7, 0, 0, 14, 6, 1, 36, 8, 5, 99, 2, 30, 21, 20, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 3, 5, 0, 5, 8, 3, 4, 0, 6, 0, 4, 9, 3, 5, 3, 28, 21, 35, 20, 25, 35, 26, 12, 7, 41, 32, 22, 9, 25, 6, 0, 2, 0, 0, 6, 3, 6, 12, 1, 15, 4, 2, 1, 0, 2, 0, 30, 21, 2, 1, 15, 21, 1, 34, 12, 25, 21, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 9, 13, 1, 4, 11, 0, 2, 27, 3, 6, 6, 0, 0, 1, 0, 33, 31, 16, 22, 14, 20, 3, 0, 1, 54, 15, 3, 22, 2, 0, 0, 0, 0, 1, 4, 0, 3, 2, 4, 2, 0, 0, 2, 13, 5, 8, 11, 4, 4, 39, 23, 35, 27, 3, 10, 14, 21, 12, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 6, 0, 2, 0, 2, 1, 1, 19, 7, 4, 11, 10, 2, 0, 21, 0, 16, 65, 1, 20, 2, 2, 42, 30, 0, 0, 0, 2, 0, 0, 0, 0, 0, 4, 3, 9, 4, 7, 0, 5, 17, 10, 1, 11, 4, 1, 7, 18, 0, 6, 22, 1, 15, 2, 12, 0, 2, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 1, 1, 10, 13, 2, 1, 2, 0, 1, 8, 1, 6, 9, 6, 0, 10, 18, 37, 24, 12, 15, 4, 35, 4, 10, 18, 24, 20, 0, 0, 0, 0, 0, 3, 1, 4, 11, 0, 0, 0, 1, 7, 2, 1, 6, 5, 22, 34, 21, 12, 22, 24, 3, 50, 4, 15, 5, 1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 4, 1, 0, 4, 14, 0, 3, 3, 1, 0, 1, 5, 4, 17, 1, 13, 3, 24, 30, 25, 27, 4, 10, 21, 2, 2, 0, 6, 0, 0, 0, 0, 0, 3, 1, 2, 6, 11, 3, 22, 13, 1, 19, 8, 14, 1, 3, 4, 5, 8, 12, 2, 25, 1, 7, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 4, 0, 3, 0, 3, 1, 6, 2, 2, 0, 0, 8, 0, 2, 5, 1, 0, 42, 52, 8, 27, 24, 41, 12, 22, 7, 4, 10, 0, 0, 0, 0, 0, 0, 1, 2, 0, 4, 5, 15, 7, 7, 10, 0, 17, 11, 7, 25, 2, 84, 28, 13, 0, 3, 4, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 2, 7, 2, 2, 5, 28, 11, 5, 0, 2, 1, 8, 0, 0, 0, 0, 0, 0, 0, 1, 8, 3, 25, 7, 5, 35, 5, 25, 69, 22, 60, 53, 8, 11, 3, 4, 1, 1, 1, 8, 6, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}};
+ return rVal;
+ }
+
+ static int[][] load_Data(String path){
+ int rVal[][] = null;
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(path));
+ String line;
+ try {
+ line = br.readLine();
+ int dim_x = Integer.parseInt(line);
+ DIMENSION = dim_x;
+ line = br.readLine();
+ int dim_y = Integer.parseInt(line);
+ rVal = new int[dim_x][dim_y];
+ int incrementer_x = 0;
+ int incrementer_y = 0;
+ while ((line = br.readLine()) != null) {
+ incrementer_y = 0;
+ while(line != ""){
+ rVal[incrementer_x][incrementer_y] = Integer.parseInt(Utilities.string_To_First_Space(line));
+ if(line.contains(" ")){
+ line = line.substring(Utilities.get_Position_Of_Next_Instance_Of_Char_In_String(line, ' ') + 1);
+ } else {
+ line = "";
+ }
+ incrementer_y++;
+ }
+ incrementer_x++;
+ }
+ } catch (IOException ex) {
+ }
+ } catch (FileNotFoundException ex) {
+ }
+ return rVal;
+ }
+
+ public static void increment_Current_Continent(){
+ current_Continent++;
+ if (current_Continent > num_Continents - 1) {
+ current_Continent = 0;
+ }
+ while(continents.get(current_Continent).size < 50){
+ current_Continent++;
+ if(current_Continent > num_Continents - 1){
+ current_Continent = 0;
+ }
+ }
+ }
+
+ public static void increment_Display_Toggle(){
+ display_toggle++;
+ if(display_toggle > max_Display_Toggle){
+ display_toggle = 0;
+ }
+ }
+
+ //the interpolation ratio applied to the statically generated terrain
+ public void setInterpolationRatio(int interpRatio){
+ interpolationRatio = interpRatio;
+ }
+
+ //the interpolation ratio applied to the dynamically generated terrain per chunk
+ public void setDynamicInterpolationRatio(int dynInterpRatio){
+ dynamicInterpRatio = dynInterpRatio;
+ }
+
+ //Sets the vertical interpolation ratio
+ public void setVerticalInterpolationRatio(int vertInterpRatio){
+ verticalInterpolationRatio = vertInterpRatio;
+ }
+
+ public void setRandomSeed(long seed){
+ Utilities.seed_Random_Functions(seed);
+ }
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/TerrainGenerator.java b/src/main/java/electrosphere/game/terrain/generation/TerrainGenerator.java
new file mode 100644
index 00000000..c44b685c
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/TerrainGenerator.java
@@ -0,0 +1,314 @@
+package electrosphere.game.terrain.generation;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Random;
+
+/**
+ *
+ * @author satellite
+ */
+class TerrainGenerator {
+ static int DIMENSION = 200;
+ static int[][] asthenosphere_Heat;
+ static int[][] rock_Hardness;
+ static int[][] elevation;
+ static int[][] smoothed_elevation;
+ static int new_Elevation[][];
+ static Vector[][] currents;
+ static ArrayList spots = new ArrayList();
+ static int Time = 0;
+ static final int ELEVATION_DATA_LENGTH = 50;
+ static int[] elevation_Data;
+ static int current_Max_Elevation_Data = 1;
+ static int lifespan = 75000;
+
+ public TerrainGenerator(){
+
+ }
+
+ public void set_Dimension(int new_Dim){
+ DIMENSION = new_Dim;
+ }
+
+ public void set_Lifespan(int new_Lifespan){
+ lifespan = new_Lifespan;
+ }
+
+
+ public void run(){
+ asthenosphere_Heat = new int[DIMENSION][DIMENSION];
+ elevation = new int[DIMENSION][DIMENSION];
+ smoothed_elevation = new int[DIMENSION][DIMENSION];
+ new_Elevation = new int[DIMENSION][DIMENSION];
+ currents = new Vector[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ currents[x][y] = new Vector();
+ }
+ }
+ elevation_Data = new int[ELEVATION_DATA_LENGTH];
+ for(int x = 0; x < ELEVATION_DATA_LENGTH; x++){
+ elevation_Data[x] = 0;
+ }
+
+
+
+
+ long last_Time = System.currentTimeMillis();
+
+
+ while(true){
+ Time++;
+ if(spots.size() >= 1){
+ ArrayList to_Remove = new ArrayList();
+ Iterator spot_Iterator = spots.iterator();
+ while(spot_Iterator.hasNext()){
+ Hotspot current_Spot = spot_Iterator.next();
+ if(current_Spot.life_current >= current_Spot.life_max){
+ to_Remove.add(current_Spot);
+ }
+ }
+ spot_Iterator = to_Remove.iterator();
+ while(spot_Iterator.hasNext()){
+ Hotspot current_Spot = spot_Iterator.next();
+ spots.remove(current_Spot);
+ }
+ }
+ if(spots.size() < 5){
+ spots.add(new Hotspot(electrosphere.game.terrain.generation.Utilities.random_Integer(0, DIMENSION - 1),electrosphere.game.terrain.generation.Utilities.random_Integer(0, DIMENSION - 1),electrosphere.game.terrain.generation.Utilities.random_Integer(6000, 10000), electrosphere.game.terrain.generation.Utilities.random_Integer(3, 5), this));
+ }
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ asthenosphere_Heat[x][y] = 0;
+ }
+ }
+ if(spots.size() >= 1){
+ Iterator spot_Iterator = spots.iterator();
+ while(spot_Iterator.hasNext()){
+ Hotspot current_Spot = spot_Iterator.next();
+ current_Spot.simulate();
+ }
+ }
+// try {
+// TimeUnit.MILLISECONDS.sleep(1);
+// } catch (InterruptedException ex) {
+// }
+ heat_To_Elevation();
+ construct_Convection_Cells();
+ apply_Vectors_To_Elevation();
+ calculate_Smoothed_Elevations();
+ if(Time % 500 == 0) {
+ long new_Time = System.currentTimeMillis();
+ long time_Delta = new_Time - last_Time;
+ last_Time = new_Time;
+ System.out.println("Progress: " + Time + "/" + lifespan + " ETA: " + (time_Delta * (lifespan - Time) / 1000 / 500) + "S");
+ }
+ if(Time > lifespan){
+ break;
+ }
+ }
+ }
+
+ public int[][] get_Terrain(){
+ return elevation;
+ }
+
+ public int[][] get_Terrain_Smoothed(){
+ return smoothed_elevation;
+ }
+
+ static void heat_To_Elevation(){
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ if(asthenosphere_Heat[x][y] > 25){
+ if(electrosphere.game.terrain.generation.Utilities.random_Integer(1, 10) == 10){
+ elevation[x][y] = elevation[x][y] + 1;
+ if(elevation[x][y] > 100){
+ elevation[x][y] = 100;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ static void construct_Convection_Cells(){
+ boolean is_cell_type_1 = false;
+ int fourth = DIMENSION / 4;
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ int normalized_x = x;
+ int normalized_y = y;
+ if(y < fourth || (y < fourth * 3 && y > (fourth * 2) - 1)){
+ is_cell_type_1 = true;
+ if(normalized_y > fourth){
+ normalized_y = normalized_y - fourth * 2;
+ }
+ } else {
+ is_cell_type_1 = false;
+ if(normalized_y > fourth * 2 + 1){
+ normalized_y = normalized_y - fourth * 3;
+ } else {
+ normalized_y = normalized_y - fourth;
+ }
+ }
+ while(normalized_x > fourth){
+ normalized_x = normalized_x - fourth;
+ }
+ if(normalized_x < 0){
+ normalized_x = 0;
+ }
+ if(normalized_y < 0){
+ normalized_y = 0;
+ }
+ int eigth = fourth / 2;
+ normalized_y = normalized_y - eigth;
+ normalized_x = normalized_x - eigth;
+ float magnitude = (float)Math.sqrt(Math.pow(normalized_y, 2) + Math.pow(normalized_x, 2));
+ if(magnitude < fourth / 10){
+ normalized_x = normalized_x + fourth / 10;
+ magnitude = (float)Math.sqrt(Math.pow(normalized_y, 2) + Math.pow(normalized_x, 2));
+ }
+ double offset_angle = Math.atan2(normalized_y / magnitude, normalized_x / magnitude);
+ if(offset_angle < 0){
+ offset_angle = offset_angle + Math.PI * 2;
+ }
+ double vector_angle = offset_angle;
+ if(is_cell_type_1){
+ offset_angle = offset_angle + Math.PI / 2;
+ } else {
+ offset_angle = offset_angle - Math.PI / 2;
+ }
+ while(offset_angle > Math.PI * 2){
+ offset_angle = offset_angle - Math.PI * 2;
+ }
+ while(offset_angle < 0){
+ offset_angle = offset_angle + Math.PI * 2;
+ }
+ currents[x][y].x = (int)(99 * Math.cos(offset_angle));
+ currents[x][y].y = (int)(99 * Math.sin(offset_angle));
+ }
+ }
+ }
+
+ static void apply_Vectors_To_Elevation(){
+ int current_Elev[][] = new int[DIMENSION][DIMENSION];
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ new_Elevation[x][y] = 0;
+ current_Elev[x][y] = elevation[x][y];
+ }
+ }
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ boolean transfer = false;
+ if (electrosphere.game.terrain.generation.Utilities.random_Integer(1, 50) == 1) {
+ transfer = true;
+ }
+ int transfer_goal;
+ if(electrosphere.game.terrain.generation.Utilities.random_Integer(1, 2)==1){
+ transfer_goal = electrosphere.game.terrain.generation.Utilities.random_Integer(20, 60);
+ } else {
+ transfer_goal = electrosphere.game.terrain.generation.Utilities.random_Integer(0, 60);
+ }
+ if(electrosphere.game.terrain.generation.Utilities.random_Integer(1, 2)==1){
+ if (currents[x][y].x >= 0) {
+ if (transfer) {
+ if (x + 1 < DIMENSION) {
+ while(new_Elevation[x + 1][y] + current_Elev[x + 1][y] < 99 && current_Elev[x][y] > transfer_goal){
+ new_Elevation[x + 1][y]++;
+ current_Elev[x][y]--;
+ }
+ } else {
+ }
+ }
+ } else {
+ if (transfer) {
+ if (x - 1 >= 0) {
+ while(new_Elevation[x - 1][y] + current_Elev[x - 1][y] < 99 && current_Elev[x][y] > transfer_goal){
+ new_Elevation[x - 1][y]++;
+ current_Elev[x][y]--;
+ }
+ } else {
+ }
+ }
+ }
+ } else {
+ if (currents[x][y].y >= 0) {
+ if (transfer) {
+ if (y + 1 < DIMENSION) { // V REPLACE THIS WITH GOAL
+ while(new_Elevation[x][y + 1] + current_Elev[x][y + 1] < 99 && current_Elev[x][y] > transfer_goal){
+ new_Elevation[x][y + 1]++;
+ current_Elev[x][y]--;
+ }
+ } else {
+ }
+ }
+ } else {
+ if (transfer) {
+ if (y - 1 >= 0) {
+ while(new_Elevation[x][y - 1] + current_Elev[x][y - 1] < 99 && current_Elev[x][y] > transfer_goal){
+ new_Elevation[x][y - 1]++;
+ current_Elev[x][y]--;
+ }
+ } else {
+ }
+ }
+ }
+ }
+ }
+ }
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ new_Elevation[x][y] = new_Elevation[x][y] + current_Elev[x][y];
+ while(new_Elevation[x][y] > 99){
+ new_Elevation[x][y] = 99;
+ }
+ elevation[x][y] = new_Elevation[x][y];
+ }
+ }
+ }
+
+ static void grab_Elevation_Data(){
+ int new_Elevation_Data_Val = 0;
+ for(int x = 0; x < DIMENSION; x++){
+ for(int y = 0; y < DIMENSION; y++){
+ new_Elevation_Data_Val = new_Elevation_Data_Val + elevation[x][y];
+ }
+ }
+ for(int x = 1; x < ELEVATION_DATA_LENGTH; x++){
+ elevation_Data[x-1] = elevation_Data[x];
+ }
+ elevation_Data[ELEVATION_DATA_LENGTH - 1] = new_Elevation_Data_Val;
+ if(new_Elevation_Data_Val > current_Max_Elevation_Data){
+ current_Max_Elevation_Data = new_Elevation_Data_Val;
+ }
+ }
+
+ static void calculate_Smoothed_Elevations(){
+ int[][] buffer = new int[DIMENSION][DIMENSION];
+ for(int x = 1; x < DIMENSION - 2; x++){
+ for(int y = 1; y < DIMENSION - 2; y++){
+ buffer[x][y] = elevation[x][y] * 4 * elevation[x+1][y] * 2 + elevation[x-1][y] * 2 + elevation[x][y+1] * 2 +
+ elevation[x][y-1] * 2 + elevation[x+1][y+1] + elevation[x+1][y-1] + elevation[x-1][y+1] + elevation[x-1][y-1];
+ buffer[x][y] = (int)(buffer[x][y] / 16.0);
+ while(buffer[x][y] > 100){
+ buffer[x][y] = buffer[x][y]/2;
+ }
+ smoothed_elevation[x][y] = buffer[x][y];
+ }
+ }
+ for(int x = 1; x < DIMENSION - 2; x++){
+ for(int y = 1; y < DIMENSION - 2; y++){
+ buffer[x][y] = smoothed_elevation[x][y] * 4 * smoothed_elevation[x+1][y] * 2 + smoothed_elevation[x-1][y] * 2 + smoothed_elevation[x][y+1] * 2 +
+ smoothed_elevation[x][y-1] * 2 + smoothed_elevation[x+1][y+1] + smoothed_elevation[x+1][y-1] + smoothed_elevation[x-1][y+1] + smoothed_elevation[x-1][y-1];
+ buffer[x][y] = (int)(buffer[x][y] / 16.0);
+ while(buffer[x][y] > 100){
+ buffer[x][y] = buffer[x][y]/2;
+ }
+ smoothed_elevation[x][y] = buffer[x][y];
+ }
+ }
+ }
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/Utilities.java b/src/main/java/electrosphere/game/terrain/generation/Utilities.java
new file mode 100644
index 00000000..9c39838c
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/Utilities.java
@@ -0,0 +1,260 @@
+package electrosphere.game.terrain.generation;
+
+import java.awt.Point;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+/**
+ *
+ * @author awhoove
+ */
+class Utilities {
+
+ static long seed = 0;
+
+ static Random rand = new Random(seed);
+
+ public static void seed_Random_Functions(long seed){
+ rand = new Random(seed);
+ }
+
+ //Finds midpoint of cluster of arbitrary points.
+ public static Point average_Points(Point[] objects){
+ Point rVal = null;
+ int x = 0;
+ int y = 0;
+ for(int i = 0; i < objects.length; i++){
+ x = x + objects[i].x;
+ y = y + objects[i].y;
+ }
+ x = x / objects.length;
+ y = y / objects.length;
+ rVal = new Point(x,y);
+ return rVal;
+ }
+ public static void sleep(int milliseconds){
+ try {
+ TimeUnit.MILLISECONDS.sleep(milliseconds);
+ } catch (InterruptedException ex) {
+ System.out.println("Sleep failed lol.");
+ }
+ }
+ public static int random_Integer(int Min, int Max){
+ return Min + (int)(rand.nextDouble() * ((Max - Min) + 1));
+ }
+ public static int random_Range_Distribution_Even(int ... range){
+ if(range.length % 2 != 0){
+ System.out.println("Invalid number of parameters for range in a function call to \"random_Range_Distribution_Even\"!");
+ return -1;
+ } else {
+ int total = 0;
+ int i = 0;
+ while(i < range.length/2 + 1){
+ total = total + range[i+1] - range[i] + 1;
+ i=i+2;
+ }
+ int temp = random_Integer(1,total);
+ int incrementer = 0;
+ i = 0;
+ while(incrementer + range[i+1] - range[i] + 1 < temp){
+ incrementer = incrementer + range[i+1] - range[i] + 1;
+ i=i+2;
+ }
+ return range[i] + (temp - incrementer) - 1;
+ }
+ }
+ public static float distance_Between_Points(Point point_One, Point point_Two){
+ float rVal = 0.0f;
+ rVal = (float)Math.sqrt(Math.pow(point_One.y - point_Two.y, 2) + Math.pow(point_One.x - point_Two.x, 2));
+ return rVal;
+ }
+ public static float angle_Between_Points(Point p1, Point p2){
+ float rVal = 0.0f;
+ rVal = (float)Math.atan2(p1.y - p2.y, p1.x - p2.x);
+ if(rVal < 0){
+ rVal = rVal + (float)(Math.PI * 2);
+ }
+ return rVal;
+ }
+
+
+ public static Point centerpoint_Of_Circle_From_Three_Points(Point p1, Point p2, Point p3){
+ Point rVal = null;
+
+ final double offset = Math.pow(p2.x, 2) + Math.pow(p2.y, 2);
+ final double bc = (Math.pow(p1.x, 2) + Math.pow(p1.y, 2) - offset) / 2.0;
+ final double cd = (offset - Math.pow(p3.x, 2) - Math.pow(p3.y, 2)) / 2.0;
+ final double det = (p1.x - p2.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p2.y);
+ if (Math.abs(det) < 0.000001) {
+ return null;
+ }
+ final double idet = 1 / det;
+
+ final double centerx = (bc * (p2.y - p3.y) - cd * (p1.y - p2.y)) * idet;
+ final double centery = (cd * (p1.x - p2.x) - bc * (p2.x - p3.x)) * idet;
+
+ return new Point((int)centerx,(int)centery);
+
+ /*
+ float slope_1 = (p2.y - p1.y) / (p2.x - p1.x);
+ float slope_2 = (p3.y - p2.y) / (p3.x - p2.x);
+ //http://paulbourke.net/geometry/circlesphere/
+ float intersect_X = (slope_1*slope_2*(p1.y-p3.y)+slope_2*(p1.x+p2.x)-slope_1*(p2.x+p3.x))/(2*(slope_2-slope_1));
+ float intersect_Y = -(1/slope_1)*(intersect_X - (p2.x+p3.x)/2)+(p2.y+p3.y)/2;
+ rVal = new Point((int)intersect_X, (int)intersect_Y);
+ return rVal;
+ */
+ }
+ public static String pull_Random_String_From_File(File source){
+ String rVal = "";
+ int line_To_Go_To;
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(source));
+ line_To_Go_To = random_Integer(1,Integer.parseInt(reader.readLine()));
+ int i = 0;
+ while(i 5000){
+ break;
+ }
+ }
+ rVal = reader.readLine();
+ } catch (FileNotFoundException ex) {
+ System.out.println("Utilities/pull_Random_String_From_File failed to read from "+source+" (File not found).");
+ } catch (IOException ex){
+ System.out.println("Utilities/pull_Random_String_From_File failed to read from "+source+" (IOException).");
+ }
+ return rVal;
+ }
+
+ public static String pull_Ordered_String_From_File(File source, int dest){
+ String rVal = "";
+ try {
+ BufferedReader reader = new BufferedReader(new FileReader(source));
+ int i = 0;
+ while(i0){
+ itterator--;
+ } else {
+ rVal = i;
+ break;
+ }
+ }
+ }
+ return rVal;
+ }
+
+ public static float[] linearize_Float_Array_Column_Major(float[][] in){
+ float[] rVal = new float[in[0].length * in.length];
+ for(int x = 0; x < in.length; x++){
+ for(int y = 0; y < in[0].length; y++){
+ rVal[x*in[0].length + y] = in[x][y];
+ }
+ }
+ return rVal;
+ }
+ public static void print_Linearized_Array(float[] in){
+ for(int i = 0; i < in.length; i++){
+ System.out.println(in[i]);
+ }
+ }
+ public static float[] linearize_Float_Array_Row_Major(float[][] in){
+ float[] rVal = new float[in[0].length * in.length];
+ for(int y = 0; y < in[0].length; y++){
+ for(int x = 0; x < in.length; x++){
+ rVal[x*in[0].length + y] = in[x][y];
+ }
+ }
+ return rVal;
+ }
+ public static String string_To_First_Space(String s){
+ String rVal = null;
+ for(int i = 0; i < s.length(); i++){
+ if(s.charAt(i)==' '){
+ rVal = s.substring(0, i);
+ break;
+ }
+ }
+ if(rVal == null){
+ rVal = s;
+ }
+ return rVal;
+ }
+ public static int position_To_First_Space(String s){
+ int rVal = -1;
+ for(int i = 0; i < s.length(); i++){
+ if(s.charAt(i)==' '){
+ rVal = i;
+ break;
+ }
+ }
+ return rVal;
+ }
+ public static int number_Of_Spaces_In_String(String s){
+ int rVal = 0;
+ for(int i = 0; i < s.length(); i++){
+ if(s.charAt(i)==' '){
+ rVal++;
+ }
+ }
+ return rVal;
+ }
+ public static String get_Face_From_OBJ_Format(String s){
+ String rVal = "";
+ int counter = 0;
+ for(int i = 0; i < s.length(); i++){
+ counter = i;
+ if(s.charAt(i)=='/'){
+ break;
+ }
+ }
+ if(counter+1 == s.length()){
+ counter++;
+ }
+ rVal = s.substring(0, counter);
+ return rVal;
+ }
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/Vector.java b/src/main/java/electrosphere/game/terrain/generation/Vector.java
new file mode 100644
index 00000000..94b9c3d5
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/Vector.java
@@ -0,0 +1,10 @@
+package electrosphere.game.terrain.generation;
+
+/**
+ *
+ * @author satellite
+ */
+class Vector {
+ public int x;
+ public int y;
+}
diff --git a/src/main/java/electrosphere/game/terrain/generation/models/TerrainModel.java b/src/main/java/electrosphere/game/terrain/generation/models/TerrainModel.java
new file mode 100644
index 00000000..3a0bdae3
--- /dev/null
+++ b/src/main/java/electrosphere/game/terrain/generation/models/TerrainModel.java
@@ -0,0 +1,694 @@
+package electrosphere.game.terrain.generation.models;
+
+import java.util.Random;
+
+public class TerrainModel {
+
+ int dynamicInterpolationRatio;
+
+ int discreteArrayDimension;
+
+ float[][] elevation;
+
+ long[][] chunkRandomizer;
+
+ float randomDampener = 0.4f;
+
+ TerrainModel() {
+
+ }
+
+ public TerrainModel(int dimension, float[][] elevation, long[][] chunkRandomizer, int dynamicInterpolationRatio){
+
+ this.dynamicInterpolationRatio = dynamicInterpolationRatio;
+ this.discreteArrayDimension = dimension;
+ this.elevation = elevation;
+ this.chunkRandomizer = chunkRandomizer;
+
+ }
+
+ public static TerrainModel constructTerrainModel(int dimension, int dynamicInterpolationRatio){
+ TerrainModel rVal = new TerrainModel();
+ rVal.discreteArrayDimension = dimension;
+ rVal.dynamicInterpolationRatio = dynamicInterpolationRatio;
+ return rVal;
+ }
+
+ public float[][] getElevation(){
+ return elevation;
+ }
+
+ public void setRandomDampener(float f){
+ randomDampener = f;
+ }
+
+ /**
+ * Dynamically interpolates a chunk of a specific size from the pre-existing elevation map
+ * @param x The x position on the elevation map to get a chunk from
+ * @param y The y position on the elevation map to get a chunk from
+ * @return Dynamically interpolated float array of elevations of chunk
+ */
+ public float[][] getElevationForChunk(int x, int y){
+
+ Random rand = new Random(chunkRandomizer[x][y]);
+ //this is what we intend to return from the function
+ float[][] rVal = new float[dynamicInterpolationRatio][dynamicInterpolationRatio];
+
+ /*
+ So we're looking at chunk x,y
+
+ if this is our grid:
+
+ 4 0.1 0.2 0.3 0.4
+ ^
+ | 3 0.1 0.2 0.3 0.4
+ |
+ | 2 0.1 0.2 0.3 0.4
+
+ x 1 0.1 0.2 0.3 0.4
+
+ 0 1 2 3
+
+ y ---- >
+
+ say we're looking at x=2,y=1
+
+ "macroValues" should contain the values for bounds x = [1,3] and y = [0,2]
+
+ the goal is to have the "center" of the output chunk have the value the
+ elevation grid at x=2,y=1
+
+ */
+
+
+ //set macroValues
+ float[][] macroValues = getMacroValuesAtPosition(x,y);
+
+
+
+
+ int halfLength = dynamicInterpolationRatio/2;
+
+ /*
+
+ Four quadrants we're generating
+
+ _____________________
+ |1 |2 |
+ | | |
+ | | |
+ | | |
+ |__________|__________|
+ |3 |4 |
+ | | |
+ | | |
+ |__________|__________|
+
+ First set of loops is quadrant 1
+ then quadrant 2
+ then quadrant 3
+ then quadrant 4
+
+ */
+
+ int outXOffset = 0;
+ int outYOffset = 0;
+
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][0] +
+ (1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
+ (1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[0][1] +
+ (1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][1]
+ ;
+ }
+ }
+
+ outXOffset = halfLength;
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
+ (1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][0] +
+ (1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][1] +
+ (1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[2][1]
+ ;
+ }
+ }
+
+ outXOffset = 0;
+ outYOffset = halfLength;
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][1] +
+ (1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
+ (1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[0][2] +
+ (1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][2]
+ ;
+ }
+ }
+
+ outXOffset = halfLength;
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
+ (1.0f * (0 - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][1] +
+ (1.0f * (halfLength - i) * (0 - j))/(halfLength * halfLength) * macroValues[1][2] +
+ (1.0f * (0 - i) * (0 - j))/(halfLength * halfLength) * macroValues[2][2]
+ ;
+ }
+ }
+
+
+ return rVal;
+ }
+
+
+ /*
+ !!!ASSUMPTIONS!!!
+ square matricies of data
+ object has already been initialized
+ dynamicInterpolationRatio is set to some valid power of 2
+ */
+
+ /**
+ * Dynamically interpolates a chunk of a specific size from the pre-existing elevation map
+ * Includes the boundary of the chunk as well
+ * @param x The x position on the elevation map to get a chunk from
+ * @param y The y position on the elevation map to get a chunk from
+ * @return Dynamically interpolated float array of elevations of chunk
+ */
+ public float[][] getAugmentedElevationForChunk(float[][] macroValues, long[][] randomizerValues){
+
+ //this is what we intend to return from the function
+ float[][] rVal = new float[dynamicInterpolationRatio+1][dynamicInterpolationRatio+1];
+
+ /*
+ So we're looking at chunk x,y
+
+ if this is our grid:
+
+ 4 0.1 0.2 0.3 0.4
+ ^
+ | 3 0.1 0.2 0.3 0.4
+ |
+ | 2 0.1 0.2 0.3 0.4
+
+ x 1 0.1 0.2 0.3 0.4
+
+ 0 1 2 3
+
+ y ---- >
+
+ say we're looking at x=2,y=1
+
+ "macroValues" should contain the values for x = [1,3] and y = [0,2]
+
+ the goal is to have the "center" of the output chunk have the value the
+ elevation grid at x=2,y=1
+
+ */
+
+
+
+ /*
+
+ Our "macro values" at the edges of this chunk need to be haldway between this chunk's center height value and the next
+ Why? think about it for a second
+
+
+ If we have some grid with chunks a and b
+
+ 0.1 0.2 0.3 0.8
+ 0.4 a b 0.9
+ 0.5 0.6 0.7 1.0
+
+
+ to generate a chunk at point a that smoothly merges into chunk b, you need
+ the chunk at a to know the value of b
+
+ but you don't want the right edge of the chunk at a to be the VALUE of b
+ because then it would work
+
+ so if we have two chunks
+
+ _____________________ _____________________
+ | | || | |
+ | | || | |
+ | | || | |
+ | | || | |
+ |__________a__________**__________b__________|
+ | | || | |
+ | | || | |
+ | | || | |
+ |__________|__________||__________|__________|
+
+ you want the value at ** to be half way between a and b
+
+ the corner cases are even worse, you have to average all four
+ _____________________ _____________________
+ | | || | |
+ | | || | |
+ | | || | |
+ | | || | |
+ |__________a__________||__________b__________|
+ | | || | |
+ | | || | |
+ | | || | |
+ |__________|__________**__________|__________|
+ _____________________**_____________________
+ | | || | |
+ | | || | |
+ | | || | |
+ | | || | |
+ |__________c__________||__________d__________|
+ | | || | |
+ | | || | |
+ | | || | |
+ |__________|__________||__________|__________|
+
+
+
+ */
+
+ float[][] newMacroValues = new float[3][3];
+ newMacroValues[0][0] = (macroValues[0][0] + macroValues[0][1] + macroValues[1][0] + macroValues[1][1]) / 4.0f;
+ newMacroValues[2][0] = (macroValues[2][0] + macroValues[2][1] + macroValues[1][0] + macroValues[1][1]) / 4.0f;
+ newMacroValues[0][2] = (macroValues[0][2] + macroValues[0][1] + macroValues[1][2] + macroValues[1][1]) / 4.0f;
+ newMacroValues[2][2] = (macroValues[2][2] + macroValues[2][1] + macroValues[1][2] + macroValues[1][1]) / 4.0f;
+ newMacroValues[1][0] = (macroValues[1][0] + macroValues[1][1]) / 2.0f;
+ newMacroValues[0][1] = (macroValues[0][1] + macroValues[1][1]) / 2.0f;
+ newMacroValues[1][2] = (macroValues[1][2] + macroValues[1][1]) / 2.0f;
+ newMacroValues[2][1] = (macroValues[2][1] + macroValues[1][1]) / 2.0f;
+ newMacroValues[1][1] = macroValues[1][1];
+
+ macroValues = newMacroValues;
+
+
+
+
+
+
+// System.out.println("discreteArrayDimension: " + discreteArrayDimension);
+
+
+
+ //The following values + random seed are what are primarily used for calculating elevation map
+ //If you want to transmit the output of this model without transmitting the entire field
+ //transmit these numbers + seeds
+
+// System.out.println("Macro values for " + x + "," + y + "\n");
+// System.out.println(macroValues[0][0] + " " + macroValues[1][0] + " " + macroValues[2][0]);
+// System.out.println(macroValues[0][1] + " " + macroValues[1][1] + " " + macroValues[2][1]);
+// System.out.println(macroValues[0][2] + " " + macroValues[1][2] + " " + macroValues[2][2]);
+// System.out.println();
+
+
+ int halfLength = dynamicInterpolationRatio/2;
+
+ /*
+
+ Four quadrants we're generating
+
+ _____________________
+ |1 |2 |
+ | | |
+ | | |
+ | | |
+ |__________|__________|
+ |3 |4 |
+ | | |
+ | | |
+ |__________|__________|
+
+ First set of loops is quadrant 1
+ then quadrant 2
+ then quadrant 3
+ then quadrant 4
+
+
+ 0,0 1,0 2,0
+ _____________________
+ |1 |2 |
+ | | |
+ | | |
+ | | |
+ 0,1 |__________|__________| 2,1
+ |3 |4 |
+ | | |
+ | | |
+ |__________|__________|
+ 0,2 1,2 2,2
+
+ Where the "macro values" correspond to on our array
+
+ */
+
+ int outXOffset = 0;
+ int outYOffset = 0;
+
+ long quadrantRandom =
+ randomizerValues[0][0] +
+ randomizerValues[1][0] +
+ randomizerValues[0][1] +
+ randomizerValues[1][1];
+
+ Random quadRand = new Random(quadrantRandom);
+
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][0] +
+ (1.0f * (i - 0) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
+ (1.0f * (halfLength - i) * (j - 0))/(halfLength * halfLength) * macroValues[0][1] +
+ (1.0f * (i - 0) * (j - 0))/(halfLength * halfLength) * macroValues[1][1] +
+ quadRand.nextFloat() * randomDampener
+ ;
+ }
+ }
+
+
+ quadrantRandom =
+ randomizerValues[1][0] +
+ randomizerValues[2][0] +
+ randomizerValues[1][1] +
+ randomizerValues[2][1];
+
+ quadRand = new Random(quadrantRandom);
+
+ outXOffset = halfLength;
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][0] +
+ (1.0f * (i - 0) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][0] +
+ (1.0f * (halfLength - i) * (j - 0))/(halfLength * halfLength) * macroValues[1][1] +
+ (1.0f * (i - 0) * (j - 0))/(halfLength * halfLength) * macroValues[2][1] +
+ quadRand.nextFloat() * randomDampener
+ ;
+ }
+ }
+
+
+
+ quadrantRandom =
+ randomizerValues[0][1] +
+ randomizerValues[1][1] +
+ randomizerValues[0][2] +
+ randomizerValues[1][2];
+
+ quadRand = new Random(quadrantRandom);
+
+ outXOffset = 0;
+ outYOffset = halfLength;
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[0][1] +
+ (1.0f * (i - 0) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
+ (1.0f * (halfLength - i) * (j - 0))/(halfLength * halfLength) * macroValues[0][2] +
+ (1.0f * (i - 0) * (j - 0))/(halfLength * halfLength) * macroValues[1][2] +
+ quadRand.nextFloat() * randomDampener
+ ;
+ }
+ }
+
+
+ quadrantRandom =
+ randomizerValues[1][1] +
+ randomizerValues[2][1] +
+ randomizerValues[1][2] +
+ randomizerValues[2][2];
+
+ quadRand = new Random(quadrantRandom);
+
+ outXOffset = halfLength;
+ for(int i = 0; i < halfLength; i++){
+ for(int j = 0; j < halfLength; j++){
+ rVal[i+outXOffset][j+outYOffset] =
+ (1.0f * (halfLength - i) * (halfLength - j))/(halfLength * halfLength) * macroValues[1][1] +
+ (1.0f * (i - 0) * (halfLength - j))/(halfLength * halfLength) * macroValues[2][1] +
+ (1.0f * (halfLength - i) * (j - 0))/(halfLength * halfLength) * macroValues[1][2] +
+ (1.0f * (i - 0) * (j - 0))/(halfLength * halfLength) * macroValues[2][2] +
+ quadRand.nextFloat() * randomDampener
+ ;
+ }
+ }
+
+
+ /*
+
+ Four quadrants we're generating
+
+ ------------>
+ _____________________
+ | |1 |2 |
+ | | | | |
+ | | | | |
+ | | | | |
+ | |__________|__________| |
+ | |3 |4 | |
+ | | | | |
+ V | | | V
+ |__________|__________|
+
+ ---------->
+
+ filling in along these arrows now
+
+
+
+ this is the "order" of the edges:
+
+
+ 1 2
+
+ 3 5
+
+
+ 4 6
+
+ 7 8
+
+
+ the corresponding randoms for each edge are
+
+ 1
+ 2 3
+ 4
+
+ */
+
+ Random edge1Rand = new Random(randomizerValues[1][1] + randomizerValues[1][0]);
+ Random edge2Rand = new Random(randomizerValues[1][1] + randomizerValues[0][1]);
+ Random edge3Rand = new Random(randomizerValues[1][1] + randomizerValues[2][1]);
+ Random edge4Rand = new Random(randomizerValues[1][1] + randomizerValues[1][2]);
+
+
+
+ for(int i = 0; i < halfLength; i++){
+ //edge 1
+ rVal[i][0] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[0][0] +
+ (1.0f * (i - 0) / halfLength) * macroValues[1][0] +
+ edge1Rand.nextFloat() * randomDampener
+ ;
+
+
+ //edge 2
+ rVal[i+halfLength][0] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[1][0] +
+ (1.0f * (i - 0) / halfLength) * macroValues[2][0] +
+ edge1Rand.nextFloat() * randomDampener
+ ;
+
+
+ //edge 3
+ rVal[0][i] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[0][0] +
+ (1.0f * (i - 0) / halfLength) * macroValues[0][1] +
+ edge2Rand.nextFloat() * randomDampener
+ ;
+
+
+ //edge 4
+ rVal[0][i+halfLength] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[0][1] +
+ (1.0f * (i - 0) / halfLength) * macroValues[0][2] +
+ edge2Rand.nextFloat() * randomDampener
+ ;
+
+ //edge 5
+ rVal[dynamicInterpolationRatio][i] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[2][0] +
+ (1.0f * (i - 0) / halfLength) * macroValues[2][1] +
+ edge3Rand.nextFloat() * randomDampener
+ ;
+
+
+ //edge 6
+ rVal[dynamicInterpolationRatio][i+halfLength] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[2][1] +
+ (1.0f * (i - 0) / halfLength) * macroValues[2][2] +
+ edge3Rand.nextFloat() * randomDampener
+ ;
+
+
+ //edge 7
+ rVal[i][dynamicInterpolationRatio] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[0][2] +
+ (1.0f * (i - 0) / halfLength) * macroValues[1][2] +
+ edge4Rand.nextFloat() * randomDampener
+ ;
+
+
+ //edge 8
+ rVal[i+halfLength][dynamicInterpolationRatio] =
+ (1.0f * (halfLength - i) / halfLength) * macroValues[1][2] +
+ (1.0f * (i - 0) / halfLength) * macroValues[2][2] +
+ edge4Rand.nextFloat() * randomDampener
+ ;
+ }
+
+ //"Because it is passed over twice" this doesn't get the right value after the loops
+ //so we do it manually to correct
+// rVal[0][dynamicInterpolationRatio] =
+// macroValues[0][2] +
+// new Random(randomizerValues[0][2] + randomizerValues[1][2]).nextFloat()
+// ;
+
+
+ //"Because array dimensions" this doesn't end up getting filled in
+ //so we have to do it manually
+ //set final corner at bottom right
+ rVal[dynamicInterpolationRatio][dynamicInterpolationRatio] =
+ macroValues[2][2] +
+ new Random(randomizerValues[1][2] + randomizerValues[2][2]).nextFloat() * randomDampener
+ ;
+
+
+ return rVal;
+ }
+
+
+
+ /*
+ So we're looking at chunk x,y
+
+ if this is our grid:
+
+ 4 0.1 0.2 0.3 0.4
+ ^
+ | 3 0.1 0.2 0.3 0.4
+ |
+ | 2 0.1 0.2 0.3 0.4
+
+ x 1 0.1 0.2 0.3 0.4
+
+ 0 1 2 3
+
+ y ---- >
+
+ say we're looking at x=2,y=1
+
+ "macroValues" should contain the values for x = [1,3] and y = [0,2]
+
+ the goal is to have the "center" of the output chunk have the value the
+ elevation grid at x=2,y=1
+
+ */
+
+ public float[][] getMacroValuesAtPosition(int x, int y){
+ float[][] rVal = new float[3][3];
+ rVal[1][1] = elevation[x][y];
+ if(x - 1 >= 0){
+ rVal[0][1] = elevation[x-1][y];
+ if(y - 1 >= 0){
+ rVal[0][0] = elevation[x-1][y-1];
+ }
+ if(y + 1 < discreteArrayDimension){
+ rVal[0][2] = elevation[x-1][y+1];
+ }
+ }
+ if(x + 1 < discreteArrayDimension){
+ rVal[2][1] = elevation[x+1][y];
+ if(y - 1 >= 0){
+ rVal[2][0] = elevation[x+1][y-1];
+ }
+ if(y + 1 < discreteArrayDimension){
+ rVal[2][2] = elevation[x+1][y+1];
+ }
+ }
+ if(y - 1 >= 0){
+ rVal[1][0] = elevation[x][y-1];
+ }
+ if(y + 1 < discreteArrayDimension){
+ rVal[1][2] = elevation[x][y+1];
+ }
+ return rVal;
+ }
+
+
+
+
+
+ /*
+ So we're looking at chunk x,y
+
+ if this is our grid:
+
+ 4 0.1 0.2 0.3 0.4
+ ^
+ | 3 0.1 0.2 0.3 0.4
+ |
+ | 2 0.1 0.2 0.3 0.4
+
+ x 1 0.1 0.2 0.3 0.4
+
+ 0 1 2 3
+
+ y ---- >
+
+ say we're looking at x=2,y=1
+
+ "macroValues" should contain the values for x = [1,3] and y = [0,2]
+
+ the goal is to have the "center" of the output chunk have the value the
+ elevation grid at x=2,y=1
+
+ */
+
+ public long[][] getRandomizerValuesAtPosition(int x, int y){
+ long[][] rVal = new long[3][3];
+ rVal[1][1] = chunkRandomizer[x][y];
+ if(x - 1 >= 0){
+ rVal[0][1] = chunkRandomizer[x-1][y];
+ if(y - 1 >= 0){
+ rVal[0][0] = chunkRandomizer[x-1][y-1];
+ }
+ if(y + 1 < discreteArrayDimension){
+ rVal[0][2] = chunkRandomizer[x-1][y+1];
+ }
+ }
+ if(x + 1 < discreteArrayDimension){
+ rVal[2][1] = chunkRandomizer[x+1][y];
+ if(y - 1 >= 0){
+ rVal[2][0] = chunkRandomizer[x+1][y-1];
+ }
+ if(y + 1 < discreteArrayDimension){
+ rVal[2][2] = chunkRandomizer[x+1][y+1];
+ }
+ }
+ if(y - 1 >= 0){
+ rVal[1][0] = chunkRandomizer[x][y-1];
+ }
+ if(y + 1 < discreteArrayDimension){
+ rVal[1][2] = chunkRandomizer[x][y+1];
+ }
+ return rVal;
+ }
+
+}
diff --git a/src/main/java/electrosphere/main/Globals.java b/src/main/java/electrosphere/main/Globals.java
index ee8d9592..1257bb86 100644
--- a/src/main/java/electrosphere/main/Globals.java
+++ b/src/main/java/electrosphere/main/Globals.java
@@ -27,6 +27,7 @@ import electrosphere.net.client.ClientNetworking;
import electrosphere.net.server.Server;
import electrosphere.renderer.ModelUtils;
import electrosphere.renderer.RenderUtils;
+import electrosphere.renderer.RenderingEngine;
import electrosphere.renderer.ShaderProgram;
import electrosphere.renderer.assetmanager.AssetDataStrings;
import electrosphere.renderer.assetmanager.AssetManager;
@@ -61,6 +62,11 @@ public class Globals {
public static MainConfig mainConfig;
+ //
+ //Rendering Engine
+ //
+ public static RenderingEngine renderingEngine;
+
//
//Client connection to server
diff --git a/src/main/java/electrosphere/main/Main.java b/src/main/java/electrosphere/main/Main.java
index f75bd4d5..98a6498e 100644
--- a/src/main/java/electrosphere/main/Main.java
+++ b/src/main/java/electrosphere/main/Main.java
@@ -5,14 +5,10 @@ import electrosphere.cfg.MainConfig;
import electrosphere.controls.ControlHandler;
import electrosphere.entity.CameraEntityUtils;
import electrosphere.entity.types.creature.CreatureUtils;
-import electrosphere.renderer.Camera;
import electrosphere.renderer.Material;
import electrosphere.renderer.Model;
import electrosphere.renderer.RenderUtils;
-import electrosphere.renderer.ShaderProgram;
-import electrosphere.renderer.texture.Texture;
import electrosphere.entity.Entity;
-import electrosphere.entity.EntityDataStrings;
import electrosphere.entity.EntityUtils;
import electrosphere.entity.state.MovementTree;
import electrosphere.entity.types.hitbox.HitboxUtils;
@@ -22,17 +18,7 @@ import electrosphere.game.state.AttachUtils;
import electrosphere.game.state.LoadingThread;
import electrosphere.game.state.SimulationState;
import electrosphere.game.state.SimulationState.SimulationStateMachine;
-import electrosphere.game.terrain.TerrainManager;
-import electrosphere.net.client.ClientNetworkMessage;
-import electrosphere.net.client.ClientNetworking;
-import electrosphere.net.server.Server;
-import electrosphere.renderer.Actor;
-import electrosphere.renderer.ui.font.FontUtils;
-import electrosphere.renderer.ModelUtils;
-import electrosphere.renderer.ui.WidgetUtils;
-import electrosphere.renderer.ui.font.TextBox;
-import electrosphere.terraingen.TerrainGen;
-import electrosphere.terraingen.models.TerrainModel;
+import electrosphere.renderer.RenderingEngine;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
@@ -42,14 +28,6 @@ import org.joml.Quaternionf;
import org.joml.Vector3f;
import org.lwjgl.glfw.*;
import static org.lwjgl.glfw.GLFW.*;
-import org.lwjgl.opengl.*;
-import static org.lwjgl.opengl.GL11.*;
-import static org.lwjgl.opengl.GL13.*;
-import static org.lwjgl.opengl.GL14.*;
-import static org.lwjgl.opengl.GL15.*;
-import static org.lwjgl.opengl.GL20.*;
-import static org.lwjgl.opengl.GL30.*;
-import static org.lwjgl.system.MemoryUtil.NULL;
import electrosphere.util.ModelLoader;
import electrosphere.util.Utilities;
import java.io.File;
@@ -62,10 +40,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
-/**
- *
- * @author amaterasu
- */
+
public class Main {
@@ -138,7 +113,8 @@ public class Main {
Globals.initGlobals();
//create the drawing context
- RenderUtils.createOpenglContext();
+ Globals.renderingEngine = new RenderingEngine();
+ Globals.renderingEngine.createOpenglContext();
//init default resources
Globals.initDefaultGraphicalResources();
@@ -274,7 +250,7 @@ public class Main {
- RenderUtils.drawScreen();
+ Globals.renderingEngine.drawScreen();
if(glfwWindowShouldClose(Globals.window)){
diff --git a/src/main/java/electrosphere/renderer/RenderUtils.java b/src/main/java/electrosphere/renderer/RenderUtils.java
index 59ba99ec..7dc12bc4 100644
--- a/src/main/java/electrosphere/renderer/RenderUtils.java
+++ b/src/main/java/electrosphere/renderer/RenderUtils.java
@@ -115,17 +115,7 @@ import static org.lwjgl.system.MemoryUtil.NULL;
*/
public class RenderUtils {
- public static final int GL_DEFAULT_FRAMEBUFFER = 0;
- public static final int GL_DEFAULT_RENDERBUFFER = 0;
- static Framebuffer screenFramebuffer;
- static Renderbuffer screenRenderbuffer;
- static int screenTextureVAO;
- static ShaderProgram screenTextureShaders;
- static ShaderProgram lightDepthShaderProgram;
- static Framebuffer lightDepthBuffer;
-
- public static boolean renderHitboxes = true;
static int createScreenTextureVAO(){
int rVal = glGenVertexArrays();
@@ -189,71 +179,7 @@ public class RenderUtils {
return rVal;
}
- public static void createOpenglContext(){
- //Sets the variables that control the window sizing
- int screenWidth = Globals.WINDOW_WIDTH;
- int screenHeight = Globals.WINDOW_HEIGHT;
- //Initializes opengl
- glfwInit();
- //Gives hints to glfw to control how opengl will be used
- glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
- glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
- glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
-// glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); Allows you to make the background transparent
-// glfwWindowHint(GLFW_OPACITY, 23);
- //Creates the window reference object
- Globals.window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", NULL, NULL);
- //Errors for failure to create window (IE: No GUI mode on linux ?)
- if (Globals.window == NULL) {
- System.out.println("Failed to make window.");
- glfwTerminate();
- }
- //Makes the window that was just created the current OS-level window context
- glfwMakeContextCurrent(Globals.window);
- //Maximize it
- glfwMaximizeWindow(Globals.window);
- //Creates the OpenGL capabilities for the program.
- GL.createCapabilities();
-
- //This enables Z-buffering so that farther-back polygons are not drawn over nearer ones
- glEnable(GL_DEPTH_TEST);
-
- // Support for transparency
- glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
- //Hide the cursor and capture it
- glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
-
-
-
- //init screen rendering quadrant
- screenTextureVAO = createScreenTextureVAO();
-// initScreenTextureShaderProgram();
- screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/simple1/simple1.vs", "/Shaders/screentexture/simple1/simple1.fs");
-// screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.vs", "/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.fs");
-
- //generate framebuffers
- screenFramebuffer = FramebufferUtils.generateScreensizeTextureFramebuffer();
- glBindFramebuffer(GL_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER);
- glBindRenderbuffer(GL_RENDERBUFFER, GL_DEFAULT_RENDERBUFFER);
-
- lightDepthShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/lightDepth/lightDepth.vs", "/Shaders/lightDepth/lightDepth.fs");
- Globals.depthMapShaderProgramLoc = lightDepthShaderProgram.shaderProgram;
- lightDepthBuffer = FramebufferUtils.generateDepthBuffer();
- Globals.shadowMapTextureLoc = lightDepthBuffer.getTexture();
-// glEnable(GL_CULL_FACE); // enabled for shadow mapping
-
-
- //
- // Projection and View matrix creation
- //
- Globals.projectionMatrix = new Matrix4f();
- Globals.viewMatrix = new Matrix4f();
- float FOV = (float)(120.0f * Math.PI /180.0f);
- Globals.projectionMatrix.setPerspective(FOV, 1.0f, 0.1f, view_Range);
- Globals.viewMatrix.translation(new Vector3f(0.0f,0.0f,-3.0f));
- }
+
public static void recaptureScreen(){
@@ -506,266 +432,6 @@ public class RenderUtils {
}
- public static void drawScreen(){
-
- //
- //first pass: generate depth map
- //
- if(Globals.RENDER_FLAG_RENDER_SHADOW_MAP){
- renderShadowMapFramebufferContent();
- }
-
-
- /*
- Render content to the game framebuffer
- */
- if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT){
- renderGameFramebufferContent();
- }
-
-
-
-
- //bind default FBO
- glBindFramebuffer(GL_FRAMEBUFFER,0);
- glDisable(GL_DEPTH_TEST);
-
- glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
-
- /*
- Render the game framebuffer texture to a quad
- */
- if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER){
- renderScreenFramebuffer();
- }
-
- /*
- Render black background
- */
- if(Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND){
- renderBlackBackground();
- }
-
- /*
- Render any ui elements
- */
- if(Globals.RENDER_FLAG_RENDER_UI){
- renderUI();
- }
-
-
-
-
-
-
- //check and call events and swap the buffers
- glfwSwapBuffers(Globals.window);
- glfwPollEvents();
- }
- static void renderShadowMapFramebufferContent(){
-
- Matrix4f modelTransformMatrix = new Matrix4f();
-
- //set the viewport to shadow map size
- glViewport(0, 0, 4096, 4096);
- glEnable(GL_DEPTH_TEST);
- lightDepthBuffer.bind();
- glClear(GL_DEPTH_BUFFER_BIT);
-
- //set matrices for light render
- float near_plane = 0.001f, far_plane = 100.5f;
- Matrix4f lightProjection = new Matrix4f().setOrtho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);//glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
- Matrix4f lightView = new Matrix4f().lookAt(
- new Vector3f(-20.0f, 40.0f, -10.0f),
- new Vector3f( 0.0f, 0.0f, 0.0f),
- new Vector3f( 0.0f, 1.0f, 0.0f)
- );
- Globals.lightDepthMatrix = new Matrix4f(lightProjection).mul(lightView);
-
- glUseProgram(lightDepthShaderProgram.shaderProgram);
- glUniformMatrix4fv(glGetUniformLocation(lightDepthShaderProgram.shaderProgram, "lightSpaceMatrix"), false, Globals.lightDepthMatrix.get(new float[16]));
-
-// glCullFace(GL_FRONT);
-
- //
- // D R A W A L L E N T I T I E S
- //
- modelTransformMatrix = new Matrix4f();
- for(Entity currentEntity : Globals.entityManager.getDrawable()){
- //fetch actor
- Actor currentActor = EntityUtils.getEntityActor(currentEntity);
- //increment animations
- if(currentActor.getCurrentAnimation() != null){
- currentActor.incrementAnimationTime(deltaTime * 500);
- }
- //calculate and apply model transform
- modelTransformMatrix.identity();
- modelTransformMatrix.translate(new Vector3f(EntityUtils.getEntityPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
- modelTransformMatrix.rotate(EntityUtils.getEntityRotation(currentEntity));
- modelTransformMatrix.scale(EntityUtils.getEntityScale(currentEntity));
- currentActor.applyModelMatrix(modelTransformMatrix);
- //draw
- currentActor.drawForDepthBuffer();
- }
-
-
-
- //bind default framebuffer
- glBindFramebuffer(GL_FRAMEBUFFER,0);
- //reset texture
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, 0);
- //reset the viewport to screen size
- glViewport(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
- //resume culling backface
-// glCullFace(GL_BACK);
- }
-
-
- static void renderGameFramebufferContent(){
-
- Matrix4f modelTransformMatrix = new Matrix4f();
-
- //bind screen fbo
- screenFramebuffer.bind();
- glEnable(GL_DEPTH_TEST);
-
- ///
- /// R E N D E R I N G S T U F F
- ///
- //Sets the background color.
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
-
- //
- // D R A W A L L E N T I T I E S
- //
- modelTransformMatrix = new Matrix4f();
- for(Entity currentEntity : Globals.entityManager.getDrawable()){
- //fetch actor
- Actor currentActor = EntityUtils.getEntityActor(currentEntity);
- //increment animations
- //this is incremented in the shadow calculations
-// if(currentActor.getCurrentAnimation() != null){
-// currentActor.incrementAnimationTime(deltaTime * 500);
-// }
- //calculate and apply model transform
- modelTransformMatrix.identity();
- modelTransformMatrix.translate(new Vector3f(EntityUtils.getEntityPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
- modelTransformMatrix.rotate(EntityUtils.getEntityRotation(currentEntity));
- modelTransformMatrix.scale(EntityUtils.getEntityScale(currentEntity));
- currentActor.applyModelMatrix(modelTransformMatrix);
- //draw
- currentActor.draw();
-
-// Model currentModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(currentEntity));
-// if(currentModel != null){
-// if(currentModel.currentAnimation != null){
-// currentModel.incrementTime(deltaTime * 500);
-// }
-// currentModel.modelMatrix = new Matrix4f();
-// currentModel.modelMatrix.translate(new Vector3f(EntityUtils.getEntityPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
-// currentModel.modelMatrix.rotate(EntityUtils.getEntityRotation(currentEntity));
-// currentModel.modelMatrix.scale(EntityUtils.getEntityScale(currentEntity));
-// currentModel.draw();
-// }
- }
-
- if(renderHitboxes){
- for(Entity currentHitbox : Globals.hitboxManager.getAllHitboxes()){
- Model hitboxModel;
- if(currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE).equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
- if((hitboxModel = Globals.assetManager.fetchModel("Models/unitsphere.fbx")) != null){
- Vector3f position = EntityUtils.getEntityPosition(currentHitbox);
- modelTransformMatrix.identity();
- modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
- // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
- modelTransformMatrix.scale((Float)currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_RADIUS) * 2);
- hitboxModel.modelMatrix = modelTransformMatrix;
- hitboxModel.draw();
- }
- } else if(currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE).equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
- if((hitboxModel = Globals.assetManager.fetchModel("Models/unitsphere_1.fbx")) != null){
- Vector3f position = EntityUtils.getEntityPosition(currentHitbox);
- modelTransformMatrix.identity();
- modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
- // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
- modelTransformMatrix.scale((Float)currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_RADIUS) * 2);
- hitboxModel.modelMatrix = modelTransformMatrix;
- hitboxModel.draw();
- }
- }
- }
- }
-
-
-
-// glBindVertexArray(0);
- }
-
- static void renderScreenFramebuffer(){
- //
- //unbind texture channels
- //
- //What does this mean?
- //essentially there are two channels we're using to draw mesh textures
- //we have to glBindTexture to pointer 0 for BOTH channels, otherwise
- //the leftover texture gets used to draw the screen framebuffer quad
- //which doesnt work
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, 0);
- glActiveTexture(GL_TEXTURE1);
- glBindTexture(GL_TEXTURE_2D, 0);
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, 0);
- glActiveTexture(GL_TEXTURE3);
- glBindTexture(GL_TEXTURE_2D, 0);
- glActiveTexture(GL_TEXTURE0);
-
-
-
- //render full screen quad
- glUseProgram(screenTextureShaders.shaderProgram);
- glBindVertexArray(screenTextureVAO);
- glBindTexture(GL_TEXTURE_2D, screenFramebuffer.getTexture());
-// glBindTexture(GL_TEXTURE_2D, lightDepthBuffer.getTexture());
- glDrawArrays(GL_TRIANGLES, 0, 6);
- glBindVertexArray(0);
- }
-
-
- static void renderUI(){
- Matrix4f modelTransformMatrix = new Matrix4f();
-
- for(Widget currentWidget : Globals.widgetManager.getWidgetList()){
- if(currentWidget.isDraw()){
- currentWidget.draw();
- }
- }
-
-// for(Entity currentEntity : Globals.entityManager.getUIElements()){
-// Actor uiActor = EntityUtils.getEntityActor(currentEntity);
-// if(currentEntity.getDataKeys().contains(EntityDataStrings.DATA_STRING_UI_ELEMENT_FONT)){
-// modelTransformMatrix.identity();
-// modelTransformMatrix.translate(EntityUtils.getEntityPosition(currentEntity));
-// uiActor.applyModelMatrix(modelTransformMatrix);
-// }
-// uiActor.drawUI();
-// }
- }
-
- static void renderBlackBackground(){
- //render full screen quad
- glUseProgram(screenTextureShaders.shaderProgram);
- glBindVertexArray(screenTextureVAO);
- Globals.blackTexture.bind();
-// glBindTexture(GL_TEXTURE_2D, screenFramebuffer.getTexture());
- glDrawArrays(GL_TRIANGLES, 0, 6);
- glBindVertexArray(0);
- }
-
}
diff --git a/src/main/java/electrosphere/renderer/RenderingEngine.java b/src/main/java/electrosphere/renderer/RenderingEngine.java
new file mode 100644
index 00000000..d768a3fd
--- /dev/null
+++ b/src/main/java/electrosphere/renderer/RenderingEngine.java
@@ -0,0 +1,412 @@
+package electrosphere.renderer;
+
+import electrosphere.entity.CameraEntityUtils;
+import electrosphere.entity.Entity;
+import electrosphere.entity.EntityDataStrings;
+import electrosphere.entity.EntityUtils;
+import electrosphere.main.Globals;
+import static electrosphere.main.Main.deltaTime;
+import static electrosphere.main.Main.view_Range;
+import static electrosphere.renderer.RenderUtils.createScreenTextureVAO;
+import electrosphere.renderer.framebuffer.Framebuffer;
+import electrosphere.renderer.framebuffer.FramebufferUtils;
+import electrosphere.renderer.framebuffer.Renderbuffer;
+import electrosphere.renderer.ui.Widget;
+import org.joml.Matrix4f;
+import org.joml.Vector3f;
+import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MAJOR;
+import static org.lwjgl.glfw.GLFW.GLFW_CONTEXT_VERSION_MINOR;
+import static org.lwjgl.glfw.GLFW.GLFW_CURSOR;
+import static org.lwjgl.glfw.GLFW.GLFW_CURSOR_DISABLED;
+import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_CORE_PROFILE;
+import static org.lwjgl.glfw.GLFW.GLFW_OPENGL_PROFILE;
+import static org.lwjgl.glfw.GLFW.glfwCreateWindow;
+import static org.lwjgl.glfw.GLFW.glfwInit;
+import static org.lwjgl.glfw.GLFW.glfwMakeContextCurrent;
+import static org.lwjgl.glfw.GLFW.glfwMaximizeWindow;
+import static org.lwjgl.glfw.GLFW.glfwPollEvents;
+import static org.lwjgl.glfw.GLFW.glfwSetInputMode;
+import static org.lwjgl.glfw.GLFW.glfwSwapBuffers;
+import static org.lwjgl.glfw.GLFW.glfwTerminate;
+import static org.lwjgl.glfw.GLFW.glfwWindowHint;
+import org.lwjgl.opengl.GL;
+import static org.lwjgl.opengl.GL11.GL_BLEND;
+import static org.lwjgl.opengl.GL11.GL_COLOR_BUFFER_BIT;
+import static org.lwjgl.opengl.GL11.GL_DEPTH_BUFFER_BIT;
+import static org.lwjgl.opengl.GL11.GL_DEPTH_TEST;
+import static org.lwjgl.opengl.GL11.GL_ONE_MINUS_SRC_ALPHA;
+import static org.lwjgl.opengl.GL11.GL_SRC_ALPHA;
+import static org.lwjgl.opengl.GL11.GL_TEXTURE_2D;
+import static org.lwjgl.opengl.GL11.GL_TRIANGLES;
+import static org.lwjgl.opengl.GL11.glBindTexture;
+import static org.lwjgl.opengl.GL11.glBlendFunc;
+import static org.lwjgl.opengl.GL11.glClear;
+import static org.lwjgl.opengl.GL11.glClearColor;
+import static org.lwjgl.opengl.GL11.glDisable;
+import static org.lwjgl.opengl.GL11.glDrawArrays;
+import static org.lwjgl.opengl.GL11.glEnable;
+import static org.lwjgl.opengl.GL11.glViewport;
+import static org.lwjgl.opengl.GL13.GL_TEXTURE0;
+import static org.lwjgl.opengl.GL13.GL_TEXTURE1;
+import static org.lwjgl.opengl.GL13.GL_TEXTURE2;
+import static org.lwjgl.opengl.GL13.GL_TEXTURE3;
+import static org.lwjgl.opengl.GL13.glActiveTexture;
+import static org.lwjgl.opengl.GL20.glGetUniformLocation;
+import static org.lwjgl.opengl.GL20.glUniformMatrix4fv;
+import static org.lwjgl.opengl.GL20.glUseProgram;
+import static org.lwjgl.opengl.GL30.GL_FRAMEBUFFER;
+import static org.lwjgl.opengl.GL30.GL_RENDERBUFFER;
+import static org.lwjgl.opengl.GL30.glBindFramebuffer;
+import static org.lwjgl.opengl.GL30.glBindRenderbuffer;
+import static org.lwjgl.opengl.GL30.glBindVertexArray;
+import static org.lwjgl.system.MemoryUtil.NULL;
+
+public class RenderingEngine {
+
+
+
+ public static final int GL_DEFAULT_FRAMEBUFFER = 0;
+ public static final int GL_DEFAULT_RENDERBUFFER = 0;
+ static Framebuffer screenFramebuffer;
+ static Renderbuffer screenRenderbuffer;
+ static int screenTextureVAO;
+ static ShaderProgram screenTextureShaders;
+
+ static ShaderProgram lightDepthShaderProgram;
+ static Framebuffer lightDepthBuffer;
+
+ public static boolean renderHitboxes = true;
+
+
+
+ public void createOpenglContext(){
+ //Sets the variables that control the window sizing
+ int screenWidth = Globals.WINDOW_WIDTH;
+ int screenHeight = Globals.WINDOW_HEIGHT;
+ //Initializes opengl
+ glfwInit();
+ //Gives hints to glfw to control how opengl will be used
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+// glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); Allows you to make the background transparent
+// glfwWindowHint(GLFW_OPACITY, 23);
+ //Creates the window reference object
+ Globals.window = glfwCreateWindow(screenWidth, screenHeight, "LearnOpenGL", NULL, NULL);
+ //Errors for failure to create window (IE: No GUI mode on linux ?)
+ if (Globals.window == NULL) {
+ System.out.println("Failed to make window.");
+ glfwTerminate();
+ }
+ //Makes the window that was just created the current OS-level window context
+ glfwMakeContextCurrent(Globals.window);
+ //Maximize it
+ glfwMaximizeWindow(Globals.window);
+ //Creates the OpenGL capabilities for the program.
+ GL.createCapabilities();
+
+ //This enables Z-buffering so that farther-back polygons are not drawn over nearer ones
+ glEnable(GL_DEPTH_TEST);
+
+ // Support for transparency
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ //Hide the cursor and capture it
+ glfwSetInputMode(Globals.window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+
+
+
+ //init screen rendering quadrant
+ screenTextureVAO = createScreenTextureVAO();
+// initScreenTextureShaderProgram();
+ screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/simple1/simple1.vs", "/Shaders/screentexture/simple1/simple1.fs");
+// screenTextureShaders = ShaderProgram.loadSpecificShader("/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.vs", "/Shaders/screentexture/drawDepthBuffer/drawDepthBuffer.fs");
+
+ //generate framebuffers
+ screenFramebuffer = FramebufferUtils.generateScreensizeTextureFramebuffer();
+ glBindFramebuffer(GL_FRAMEBUFFER, GL_DEFAULT_FRAMEBUFFER);
+ glBindRenderbuffer(GL_RENDERBUFFER, GL_DEFAULT_RENDERBUFFER);
+
+ lightDepthShaderProgram = ShaderProgram.loadSpecificShader("/Shaders/lightDepth/lightDepth.vs", "/Shaders/lightDepth/lightDepth.fs");
+ Globals.depthMapShaderProgramLoc = lightDepthShaderProgram.shaderProgram;
+ lightDepthBuffer = FramebufferUtils.generateDepthBuffer();
+ Globals.shadowMapTextureLoc = lightDepthBuffer.getTexture();
+// glEnable(GL_CULL_FACE); // enabled for shadow mapping
+
+
+ //
+ // Projection and View matrix creation
+ //
+ Globals.projectionMatrix = new Matrix4f();
+ Globals.viewMatrix = new Matrix4f();
+ float FOV = (float)(120.0f * Math.PI /180.0f);
+ Globals.projectionMatrix.setPerspective(FOV, 1.0f, 0.1f, view_Range);
+ Globals.viewMatrix.translation(new Vector3f(0.0f,0.0f,-3.0f));
+ }
+
+
+ public void drawScreen(){
+
+ //
+ //first pass: generate depth map
+ //
+ if(Globals.RENDER_FLAG_RENDER_SHADOW_MAP){
+ renderShadowMapFramebufferContent();
+ }
+
+
+ /*
+ Render content to the game framebuffer
+ */
+ if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER_CONTENT){
+ renderGameFramebufferContent();
+ }
+
+
+
+
+ //bind default FBO
+ glBindFramebuffer(GL_FRAMEBUFFER,0);
+ glDisable(GL_DEPTH_TEST);
+
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /*
+ Render the game framebuffer texture to a quad
+ */
+ if(Globals.RENDER_FLAG_RENDER_SCREEN_FRAMEBUFFER){
+ renderScreenFramebuffer();
+ }
+
+ /*
+ Render black background
+ */
+ if(Globals.RENDER_FLAG_RENDER_BLACK_BACKGROUND){
+ renderBlackBackground();
+ }
+
+ /*
+ Render any ui elements
+ */
+ if(Globals.RENDER_FLAG_RENDER_UI){
+ renderUI();
+ }
+
+
+
+
+
+
+ //check and call events and swap the buffers
+ glfwSwapBuffers(Globals.window);
+ glfwPollEvents();
+ }
+
+
+ static void renderShadowMapFramebufferContent(){
+
+ Matrix4f modelTransformMatrix = new Matrix4f();
+
+ //set the viewport to shadow map size
+ glViewport(0, 0, 4096, 4096);
+ glEnable(GL_DEPTH_TEST);
+ lightDepthBuffer.bind();
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ //set matrices for light render
+ float near_plane = 0.001f, far_plane = 100.5f;
+ Matrix4f lightProjection = new Matrix4f().setOrtho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);//glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
+ Matrix4f lightView = new Matrix4f().lookAt(
+ new Vector3f(-20.0f, 40.0f, -10.0f),
+ new Vector3f( 0.0f, 0.0f, 0.0f),
+ new Vector3f( 0.0f, 1.0f, 0.0f)
+ );
+ Globals.lightDepthMatrix = new Matrix4f(lightProjection).mul(lightView);
+
+ glUseProgram(lightDepthShaderProgram.shaderProgram);
+ glUniformMatrix4fv(glGetUniformLocation(lightDepthShaderProgram.shaderProgram, "lightSpaceMatrix"), false, Globals.lightDepthMatrix.get(new float[16]));
+
+// glCullFace(GL_FRONT);
+
+ //
+ // D R A W A L L E N T I T I E S
+ //
+ modelTransformMatrix = new Matrix4f();
+ for(Entity currentEntity : Globals.entityManager.getDrawable()){
+ //fetch actor
+ Actor currentActor = EntityUtils.getEntityActor(currentEntity);
+ //increment animations
+ if(currentActor.getCurrentAnimation() != null){
+ currentActor.incrementAnimationTime(deltaTime * 500);
+ }
+ //calculate and apply model transform
+ modelTransformMatrix.identity();
+ modelTransformMatrix.translate(new Vector3f(EntityUtils.getEntityPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
+ modelTransformMatrix.rotate(EntityUtils.getEntityRotation(currentEntity));
+ modelTransformMatrix.scale(EntityUtils.getEntityScale(currentEntity));
+ currentActor.applyModelMatrix(modelTransformMatrix);
+ //draw
+ currentActor.drawForDepthBuffer();
+ }
+
+
+
+ //bind default framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER,0);
+ //reset texture
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ //reset the viewport to screen size
+ glViewport(0, 0, Globals.WINDOW_WIDTH, Globals.WINDOW_HEIGHT);
+ //resume culling backface
+// glCullFace(GL_BACK);
+ }
+
+
+ static void renderGameFramebufferContent(){
+
+ Matrix4f modelTransformMatrix = new Matrix4f();
+
+ //bind screen fbo
+ screenFramebuffer.bind();
+ glEnable(GL_DEPTH_TEST);
+
+ ///
+ /// R E N D E R I N G S T U F F
+ ///
+ //Sets the background color.
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+ //
+ // D R A W A L L E N T I T I E S
+ //
+ modelTransformMatrix = new Matrix4f();
+ for(Entity currentEntity : Globals.entityManager.getDrawable()){
+ //fetch actor
+ Actor currentActor = EntityUtils.getEntityActor(currentEntity);
+ //increment animations
+ //this is incremented in the shadow calculations
+// if(currentActor.getCurrentAnimation() != null){
+// currentActor.incrementAnimationTime(deltaTime * 500);
+// }
+ //calculate and apply model transform
+ modelTransformMatrix.identity();
+ modelTransformMatrix.translate(new Vector3f(EntityUtils.getEntityPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
+ modelTransformMatrix.rotate(EntityUtils.getEntityRotation(currentEntity));
+ modelTransformMatrix.scale(EntityUtils.getEntityScale(currentEntity));
+ currentActor.applyModelMatrix(modelTransformMatrix);
+ //draw
+ currentActor.draw();
+
+// Model currentModel = Globals.assetManager.fetchModel(EntityUtils.getEntityModelPath(currentEntity));
+// if(currentModel != null){
+// if(currentModel.currentAnimation != null){
+// currentModel.incrementTime(deltaTime * 500);
+// }
+// currentModel.modelMatrix = new Matrix4f();
+// currentModel.modelMatrix.translate(new Vector3f(EntityUtils.getEntityPosition(currentEntity)).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
+// currentModel.modelMatrix.rotate(EntityUtils.getEntityRotation(currentEntity));
+// currentModel.modelMatrix.scale(EntityUtils.getEntityScale(currentEntity));
+// currentModel.draw();
+// }
+ }
+
+ if(renderHitboxes){
+ for(Entity currentHitbox : Globals.hitboxManager.getAllHitboxes()){
+ Model hitboxModel;
+ if(currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE).equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HURT)){
+ if((hitboxModel = Globals.assetManager.fetchModel("Models/unitsphere.fbx")) != null){
+ Vector3f position = EntityUtils.getEntityPosition(currentHitbox);
+ modelTransformMatrix.identity();
+ modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
+ // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
+ modelTransformMatrix.scale((Float)currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_RADIUS) * 2);
+ hitboxModel.modelMatrix = modelTransformMatrix;
+ hitboxModel.draw();
+ }
+ } else if(currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE).equals(EntityDataStrings.COLLISION_ENTITY_DATA_TYPE_HIT)){
+ if((hitboxModel = Globals.assetManager.fetchModel("Models/unitsphere_1.fbx")) != null){
+ Vector3f position = EntityUtils.getEntityPosition(currentHitbox);
+ modelTransformMatrix.identity();
+ modelTransformMatrix.translate(new Vector3f(position).sub(CameraEntityUtils.getCameraCenter(Globals.playerCamera)).sub(new Vector3f(0,1,0)));
+ // modelTransformMatrix.translate(-0.25f, 0.0f, 0.5f); //center sphere
+ modelTransformMatrix.scale((Float)currentHitbox.getData(EntityDataStrings.COLLISION_ENTITY_DATA_RADIUS) * 2);
+ hitboxModel.modelMatrix = modelTransformMatrix;
+ hitboxModel.draw();
+ }
+ }
+ }
+ }
+
+
+
+// glBindVertexArray(0);
+ }
+
+ static void renderScreenFramebuffer(){
+ //
+ //unbind texture channels
+ //
+ //What does this mean?
+ //essentially there are two channels we're using to draw mesh textures
+ //we have to glBindTexture to pointer 0 for BOTH channels, otherwise
+ //the leftover texture gets used to draw the screen framebuffer quad
+ //which doesnt work
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE3);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glActiveTexture(GL_TEXTURE0);
+
+
+
+ //render full screen quad
+ glUseProgram(screenTextureShaders.shaderProgram);
+ glBindVertexArray(screenTextureVAO);
+ glBindTexture(GL_TEXTURE_2D, screenFramebuffer.getTexture());
+// glBindTexture(GL_TEXTURE_2D, lightDepthBuffer.getTexture());
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindVertexArray(0);
+ }
+
+
+ static void renderUI(){
+ Matrix4f modelTransformMatrix = new Matrix4f();
+
+ for(Widget currentWidget : Globals.widgetManager.getWidgetList()){
+ if(currentWidget.isDraw()){
+ currentWidget.draw();
+ }
+ }
+
+// for(Entity currentEntity : Globals.entityManager.getUIElements()){
+// Actor uiActor = EntityUtils.getEntityActor(currentEntity);
+// if(currentEntity.getDataKeys().contains(EntityDataStrings.DATA_STRING_UI_ELEMENT_FONT)){
+// modelTransformMatrix.identity();
+// modelTransformMatrix.translate(EntityUtils.getEntityPosition(currentEntity));
+// uiActor.applyModelMatrix(modelTransformMatrix);
+// }
+// uiActor.drawUI();
+// }
+ }
+
+ static void renderBlackBackground(){
+ //render full screen quad
+ glUseProgram(screenTextureShaders.shaderProgram);
+ glBindVertexArray(screenTextureVAO);
+ Globals.blackTexture.bind();
+// glBindTexture(GL_TEXTURE_2D, screenFramebuffer.getTexture());
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+ glBindVertexArray(0);
+ }
+
+
+}