Improved code readability master
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Thu, 27 Jul 2023 06:51:33 +0000 (09:51 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Thu, 27 Jul 2023 06:51:33 +0000 (09:51 +0300)
21 files changed:
pom.xml
src/main/java/eu/svjatoslav/sixth/e3d/examples/GraphDemo.java
src/main/java/eu/svjatoslav/sixth/e3d/examples/OctreeDemo.java
src/main/java/eu/svjatoslav/sixth/e3d/examples/PointCloudDemo.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/Galaxy.java [new file with mode: 0755]
src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/PointCloudDemo.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/ApplicationListPanel.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/Main.java
src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/MenuPanel.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Cell.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Main.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Matrix.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Star.java [deleted file]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Cell.java [new file with mode: 0755]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Main.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Matrix.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Star.java [new file with mode: 0644]
tools/commit and push
tools/debug [deleted file]
tools/open with IntelliJ IDEA
tools/update web site

diff --git a/pom.xml b/pom.xml
index 6f2ceeb..96ce3fb 100644 (file)
--- a/pom.xml
+++ b/pom.xml
         <repository>
             <id>svjatoslav.eu</id>
             <name>Svjatoslav repository</name>
-            <url>https://www2.svjatoslav.eu/maven/</url>
+            <url>https://www3.svjatoslav.eu/maven/</url>
         </repository>
     </repositories>
 
index f644c3a..3dd9303 100755 (executable)
@@ -24,6 +24,7 @@ public class GraphDemo {
     private static final double WAVE_FREQUENCY = 50d;
     private static final double WAVE_AMPLITUDE = 50d;
     private static final Color SQUARE_PLATE_COLOR = new Color("88F7");
+    private static final double GRAPH_SCALE = 50d;
 
     private static void makeSquarePlate(final ShapeCollection shapeCollection,
                                         final double y, final double x, final double z) {
@@ -55,8 +56,6 @@ public class GraphDemo {
             }
     }
 
-    private static final double scale = 50d;
-
     private static Graph getCosineGraph(final Point3D location) {
         final List<Point2D> data = new ArrayList<>();
         for (double x = 0; x < 20; x += 0.25) {
@@ -66,7 +65,7 @@ public class GraphDemo {
             data.add(p);
         }
 
-        return new Graph(scale, data, "Cosine", location);
+        return new Graph(GRAPH_SCALE, data, "Cosine", location);
     }
 
     private static Graph getFormula1Graph(final Point3D location) {
@@ -78,7 +77,7 @@ public class GraphDemo {
             data.add(p);
         }
 
-        return new Graph(scale, data, "y = sin(tan(x))", location);
+        return new Graph(GRAPH_SCALE, data, "y = sin(tan(x))", location);
     }
 
     private static Graph getFormula2Graph(final Point3D location) {
@@ -90,7 +89,7 @@ public class GraphDemo {
             data.add(p);
         }
 
-        return new Graph(scale, data, "y = ( (10-x)^2 ) / 30", location);
+        return new Graph(GRAPH_SCALE, data, "y = ( (10-x)^2 ) / 30", location);
     }
 
     private static Graph getFormula3Graph(final Point3D location) {
@@ -102,7 +101,7 @@ public class GraphDemo {
             data.add(p);
         }
 
-        return new Graph(scale, data, "y = sin(x/2) + sin(x/1.26)", location);
+        return new Graph(GRAPH_SCALE, data, "y = sin(x/2) + sin(x/1.26)", location);
     }
 
     private static Graph getSineGraph(final Point3D location) {
@@ -114,7 +113,7 @@ public class GraphDemo {
             data.add(p);
         }
 
-        return new Graph(scale, data, "Sine", location);
+        return new Graph(GRAPH_SCALE, data, "Sine", location);
     }
 
     private static Graph getTangentGraph(final Point3D location) {
@@ -131,7 +130,7 @@ public class GraphDemo {
             data.add(p);
         }
 
-        return new Graph(scale, data, "Tangent", location);
+        return new Graph(GRAPH_SCALE, data, "Tangent", location);
     }
 
     public static void main(final String[] args) {
index 7b733cb..e9979dc 100755 (executable)
@@ -11,6 +11,7 @@ import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
 import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
 import eu.svjatoslav.sixth.e3d.gui.humaninput.WorldNavigationUserInputTracker;
 import eu.svjatoslav.sixth.e3d.math.Transform;
+import eu.svjatoslav.sixth.e3d.renderer.octree.IntegerPoint;
 import eu.svjatoslav.sixth.e3d.renderer.octree.OctreeVolume;
 import eu.svjatoslav.sixth.e3d.renderer.octree.raytracer.Camera;
 import eu.svjatoslav.sixth.e3d.renderer.octree.raytracer.LightSource;
@@ -75,7 +76,9 @@ public class OctreeDemo extends WorldNavigationUserInputTracker {
         final double c2 = (Math.cos(x / 10f) * 100f) + 127;
         final double c3 = (Math.cos(z / 12f) * 100f) + 127;
 
-        putRect(x - size, y - size, z - size, x + size, y + size, z + size,
+        putRect(
+                new IntegerPoint( x - size, y - size, z - size),
+                new IntegerPoint( x + size, y + size, z + size),
                 new Color((int) c1, (int) c2, (int) c3, 100));
 
         if (size > 1) {
@@ -109,16 +112,24 @@ public class OctreeDemo extends WorldNavigationUserInputTracker {
         dotSpiral();
 
         // arbitrary rectangles
-        putRect(-10, -10, -10, 10, 10, -20, new Color(200, 255, 200, 100));
-        putRect(-3, 0, -30, 12, 3, 300, new Color(255, 200, 200, 100));
-        putRect(-20, 20, -20, 20, 80, 20, new Color(255, 200, 255, 100));
+        putRect(new IntegerPoint(-10, -10, -10),
+                new IntegerPoint(10, 10, -20),
+                new Color(200, 255, 200, 100));
+
+        putRect(new IntegerPoint(-3, 0, -30),
+                new IntegerPoint( 12, 3, 300),
+                new Color(255, 200, 200, 100));
+
+        putRect(new IntegerPoint(-20, 20, -20),
+                new IntegerPoint(20, 80, 20),
+                new Color(255, 200, 255, 100));
 
         tiledFloor();
 
         fractal(-50, 20, 100, 32, 1);
 
         final TextCanvas message = new TextCanvas(new Transform(new Point3D(
-                -10, 20, -180)), "Press \"r\" to raytrace current wiew",
+                -10, 20, -180)), "Press \"r\" to raytrace current view",
                 Color.WHITE, Color.PURPLE);
         shapeCollection.addShape(message);
 
@@ -144,15 +155,14 @@ public class OctreeDemo extends WorldNavigationUserInputTracker {
 
     }
 
-    private void putRect(final int x1, final int y1, final int z1, final int x2,
-                         final int y2, final int z2, final Color color) {
+    private void putRect(IntegerPoint p1, IntegerPoint p2, final Color color) {
 
         shapeCollection
                 .addShape(new SolidPolygonRectangularBox(
-                        new Point3D(x1, y1, z1).scaleUp(magnification),
-                        new Point3D(x2, y2, z2).scaleUp(magnification), color));
+                        new Point3D(p1).scaleUp(magnification),
+                        new Point3D(p2).scaleUp(magnification), color));
 
-        octreeVolume.fillRect3D(x1, y1, z1, x2, y2, z2, color);
+        octreeVolume.fillRectangle(p1, p2, color);
     }
 
     private void raytrace() {
@@ -170,10 +180,13 @@ public class OctreeDemo extends WorldNavigationUserInputTracker {
     private void tiledFloor() {
         final int step = 40;
         final int size = step - 15;
+        Color color = new Color(255, 255, 255, 100);
         for (int x = -200; x < 200; x += step)
             for (int z = -200; z < 200; z += step)
-                putRect(x, 100, z, x + size, 110, z + size, new Color(255, 255,
-                        255, 100));
+                putRect(
+                        new IntegerPoint(x, 100, z),
+                        new IntegerPoint(x + size, 110, z + size),
+                        color);
     }
 
 }
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/PointCloudDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/PointCloudDemo.java
deleted file mode 100644 (file)
index 8e36080..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Sixth 3D engine demos. Author: Svjatoslav Agejenko. 
- * This project is released under Creative Commons Zero (CC0) license.
- *
-*/
-
-package eu.svjatoslav.sixth.e3d.examples;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
-import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
-import eu.svjatoslav.sixth.e3d.math.Transform;
-import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.Galaxy;
-
-public class PointCloudDemo {
-
-    public static void main(final String[] args) {
-
-        final ViewFrame viewFrame = new ViewFrame();
-
-        final ShapeCollection geometryCollection = viewFrame.getViewPanel()
-                .getRootShapeCollection();
-
-        Transform transform = new Transform(new Point3D(0, -1000, 1000), 0, 0);
-
-        // add galaxy
-        geometryCollection.addShape(new Galaxy(500, 3, 10000, transform));
-
-    }
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/Galaxy.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/Galaxy.java
new file mode 100755 (executable)
index 0000000..73764a9
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Sixth 3D engine. Author: Svjatoslav Agejenko. 
+ * This project is released under Creative Commons Zero (CC0) license.
+ */
+package eu.svjatoslav.sixth.e3d.examples.galaxy_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.math.Transform;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.GlowingPoint;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import static java.lang.Math.*;
+
+public class Galaxy extends AbstractCompositeShape {
+
+    /**
+     * The number of unique colors used in the galaxy.
+     */
+    public static final int UNIQUE_COLORS_COUNT = 30;
+
+    /**
+     * A list of all colors used in the galaxy.
+     * Used to reuse textures of glowing points of the same color.
+     */
+    private static List<Color> colors;
+
+    public Galaxy(final int galaxySize, final int tailCount, final int starsCount,
+                  Transform transform) {
+
+        super(transform);
+
+        ensureColorsAreInitialized();
+
+        final double angle1 = random() * 10;
+        final double angle2 = random() * 10;
+
+        final double angleSin1 = sin(angle1);
+        final double angleCos1 = cos(angle1);
+        final double angleSin2 = sin(angle2);
+        final double angleCos2 = cos(angle2);
+
+        Random random = new Random();
+
+        double starSize = galaxySize / 70d;
+
+        for (int i = 1; i < starsCount; i++) {
+            final double b = random() * 10;
+
+            final double s = (b * b) / 30;
+
+            final double v1 = (random() * (11.5 - b)) / 3;
+            final double v1p = v1 / 2;
+
+            final double ane = ((random() * (s / 2)) / tailCount) * 2;
+            final double sba = ((2 * PI) / tailCount)
+                    * random.nextInt(tailCount);
+
+            final double x = (((sin((b - sba) + ane) * s) + (random() * v1)) - v1p) * galaxySize;
+            final double z = (((cos((b - sba) + ane) * s) + (random() * v1)) - v1p) * galaxySize;
+            final double y = ((random() * v1) - v1p) * galaxySize;
+
+            final double x1 = (x * angleCos1) + (z * angleSin1);
+            final double z1 = (z * angleCos1) - (x * angleSin1);
+
+            final double y1 = (y * angleCos2) + (z1 * angleSin2);
+            final double z2 = (z1 * angleCos2) - (y * angleSin2);
+
+            addStar(new Point3D(x1, y1, z2), starSize);
+        }
+    }
+
+    private void addStar(final Point3D starLocation, double size) {
+        addShape(new GlowingPoint(starLocation, size, colors.get((int) (random() * colors.size()))));
+    }
+
+    /**
+     * Initializes the list of colors used in the galaxy.
+     * Used to reuse textures of glowing points of the same color.
+     */
+    private synchronized void ensureColorsAreInitialized() {
+        if (colors != null) return;
+
+        colors = new ArrayList<>();
+
+        for (int i = 0; i < UNIQUE_COLORS_COUNT; i++)
+            colors.add(
+                    new Color(
+                            random() + 0.5,
+                            random() + 0.5,
+                            random() + 0.5,
+                            255));
+    }
+
+}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/PointCloudDemo.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/galaxy_demo/PointCloudDemo.java
new file mode 100644 (file)
index 0000000..6ce037b
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko. 
+ * This project is released under Creative Commons Zero (CC0) license.
+ *
+*/
+
+package eu.svjatoslav.sixth.e3d.examples.galaxy_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
+import eu.svjatoslav.sixth.e3d.math.Transform;
+import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
+
+public class PointCloudDemo {
+
+    public static void main(final String[] args) {
+
+        final ViewFrame viewFrame = new ViewFrame();
+
+        final ShapeCollection geometryCollection = viewFrame.getViewPanel()
+                .getRootShapeCollection();
+
+        Transform transform = new Transform(new Point3D(0, -1000, 1000), 0, 0);
+
+        // add galaxy
+        geometryCollection.addShape(new Galaxy(500, 3, 10000, transform));
+
+    }
+}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/ApplicationListPanel.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/ApplicationListPanel.java
new file mode 100644 (file)
index 0000000..ab41bf3
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Sixth 3D engine demos. Author: Svjatoslav Agejenko. 
+ * This project is released under Creative Commons Zero (CC0) license.
+ *
+*/
+
+package eu.svjatoslav.sixth.e3d.examples.launcher;
+
+import eu.svjatoslav.sixth.e3d.examples.*;
+import eu.svjatoslav.sixth.e3d.examples.galaxy_demo.PointCloudDemo;
+
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+
+class ApplicationListPanel extends JPanel {
+    private static final long serialVersionUID = 2012721856427052560L;
+
+    ApplicationListPanel() {
+        final GroupLayout groupLayout = new GroupLayout(this);
+        GroupLayout.SequentialGroup sequentialGroup = groupLayout.createSequentialGroup();
+        sequentialGroup.addComponent(new JLabel("Choose an example to launch:"));
+        sequentialGroup.addComponent(new JButton(new ShowOctree()));
+        sequentialGroup.addComponent(new JButton(new ShowMathGraphs()));
+        sequentialGroup.addComponent(new JButton(new ShowPointCloud()));
+        sequentialGroup.addComponent(new JButton(new ShowRain()));
+        sequentialGroup.addComponent(new JButton(new ShowTextEditors()));
+        sequentialGroup.addComponent(new JButton(new ShowTextEditors2()));
+        sequentialGroup.addComponent(new JButton(new ShowGameOfLife()));
+        sequentialGroup.addComponent(new JButton(new ShowRandomPolygons()));
+    }
+
+    private static class ShowTextEditors extends AbstractAction {
+        ShowTextEditors() {
+            putValue(NAME, "Text editors");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            TextEditorDemo.main(null);
+        }
+    }
+
+    private static class ShowTextEditors2 extends AbstractAction {
+        ShowTextEditors2() {
+            putValue(NAME, "Text editors city");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            TextEditorDemo2.main(null);
+        }
+    }
+
+
+    private static class ShowRain extends AbstractAction {
+        ShowRain() {
+            putValue(NAME, "Raining numbers");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            RainingNumbersDemo.main(null);
+        }
+    }
+
+    private static class ShowPointCloud extends AbstractAction {
+        ShowPointCloud() {
+            putValue(NAME, "Point cloud galaxy");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            PointCloudDemo.main(null);
+        }
+    }
+
+    private static class ShowMathGraphs extends AbstractAction {
+        ShowMathGraphs() {
+            putValue(NAME, "Mathematical graphs");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            GraphDemo.main(null);
+        }
+    }
+
+    private static class ShowRandomPolygons extends AbstractAction {
+        ShowRandomPolygons() {
+            putValue(NAME, "Random polygons");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            RandomPolygonsDemo.main(null);
+        }
+    }
+
+    private static class ShowOctree extends AbstractAction {
+        ShowOctree() {
+            putValue(NAME, "Volumetric Octree");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            OctreeDemo.main(null);
+        }
+    }
+
+    private static class ShowGameOfLife extends AbstractAction {
+        ShowGameOfLife() {
+            putValue(NAME, "Game of Life");
+        }
+
+        @Override
+        public void actionPerformed(final ActionEvent e) {
+            eu.svjatoslav.sixth.e3d.examples.life_demo.Main.main(null);
+        }
+    }
+
+}
index 4d090f8..0d15f43 100755 (executable)
@@ -9,29 +9,31 @@ package eu.svjatoslav.sixth.e3d.examples.launcher;
 import javax.swing.*;
 import java.awt.*;
 
-class Main extends javax.swing.JFrame {
+import static java.awt.BorderLayout.CENTER;
+import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;
 
-    private static final long serialVersionUID = -3679656169594556137L;
 
-    private Main() {
-        super();
-        initGUI();
-    }
+class Main {
 
     public static void main(final String[] args) {
-        SwingUtilities.invokeLater(() -> {
-            final Main inst = new Main();
-            final BorderLayout instLayout = new BorderLayout();
-            inst.setLocationRelativeTo(null);
-            inst.setVisible(true);
-            inst.getContentPane().setLayout(instLayout);
-        });
+        buildAndShowGuiWindow();
     }
 
-    private void initGUI() {
-        getContentPane().add(new MenuPanel());
-        pack();
-        setSize(390, 300);
+    /**
+     * Builds and shows the main window of the application.
+     */
+    private static void buildAndShowGuiWindow() {
+        JFrame frame = new JFrame("Sixth 3D engine demos");
+
+        // Keep application running until last frame is closed.
+        frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
+
+        frame.getContentPane().setLayout(new BorderLayout());
+        frame.getContentPane().add(new ApplicationListPanel(), CENTER);
+        frame.setSize(400, 300);
+
+        frame.setLocationRelativeTo(null); // center frame on screen
+        frame.setVisible(true);
     }
 
 }
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/MenuPanel.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/MenuPanel.java
deleted file mode 100644 (file)
index e620649..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Sixth 3D engine demos. Author: Svjatoslav Agejenko. 
- * This project is released under Creative Commons Zero (CC0) license.
- *
-*/
-
-package eu.svjatoslav.sixth.e3d.examples.launcher;
-
-import eu.svjatoslav.sixth.e3d.examples.*;
-
-import javax.swing.*;
-import java.awt.event.ActionEvent;
-
-class MenuPanel extends JPanel {
-    private static final long serialVersionUID = 2012721856427052560L;
-
-    MenuPanel() {
-        final GroupLayout groupLayout = new GroupLayout(this);
-        GroupLayout.SequentialGroup sequentialGroup = groupLayout.createSequentialGroup();
-        sequentialGroup.addComponent(new JLabel("Choose an example to launch:"));
-        sequentialGroup.addComponent(new JButton(new ShowOctree()));
-        sequentialGroup.addComponent(new JButton(new ShowMathGraphs()));
-        sequentialGroup.addComponent(new JButton(new ShowPointCloud()));
-        sequentialGroup.addComponent(new JButton(new ShowRain()));
-        sequentialGroup.addComponent(new JButton(new ShowTextEditors()));
-        sequentialGroup.addComponent(new JButton(new ShowTextEditors2()));
-        sequentialGroup.addComponent(new JButton(new ShowGameOfLife()));
-        sequentialGroup.addComponent(new JButton(new ShowRandomPolygons()));
-    }
-
-    private static class ShowTextEditors extends AbstractAction {
-        ShowTextEditors() {
-            putValue(NAME, "Text editors");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            TextEditorDemo.main(null);
-        }
-    }
-
-    private static class ShowTextEditors2 extends AbstractAction {
-        ShowTextEditors2() {
-            putValue(NAME, "Text editors city");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            TextEditorDemo2.main(null);
-        }
-    }
-
-
-    private static class ShowRain extends AbstractAction {
-        ShowRain() {
-            putValue(NAME, "Raining numbers");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            RainingNumbersDemo.main(null);
-        }
-    }
-
-    private static class ShowPointCloud extends AbstractAction {
-        ShowPointCloud() {
-            putValue(NAME, "Pointcloud galaxy");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            PointCloudDemo.main(null);
-        }
-    }
-
-    private static class ShowMathGraphs extends AbstractAction {
-        ShowMathGraphs() {
-            putValue(NAME, "Mathematical graphs");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            GraphDemo.main(null);
-        }
-    }
-
-    private static class ShowRandomPolygons extends AbstractAction {
-        ShowRandomPolygons() {
-            putValue(NAME, "Random polygons");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            RandomPolygonsDemo.main(null);
-        }
-    }
-
-    private static class ShowOctree extends AbstractAction {
-        ShowOctree() {
-            putValue(NAME, "Volumetric Octree");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            OctreeDemo.main(null);
-        }
-    }
-
-    private static class ShowGameOfLife extends AbstractAction {
-        ShowGameOfLife() {
-            putValue(NAME, "Game of Life");
-        }
-
-        @Override
-        public void actionPerformed(final ActionEvent e) {
-            eu.svjatoslav.sixth.e3d.examples.life.Main.main(null);
-        }
-    }
-
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Cell.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Cell.java
deleted file mode 100755 (executable)
index fb78e4b..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-package eu.svjatoslav.sixth.e3d.examples.life;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
-import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
-import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
-
-/**
- * This class corresponds to a single cell within matrix.
- */
-class Cell extends AbstractCompositeShape implements
-        MouseInteractionController {
-
-    /**
-     * cell visual size
-     */
-    static final int SIZE = 20;
-    /**
-     * Color of the active cell (R, G, B, A)
-     */
-    private static final Color ACTIVE_COLOR = new Color("A8FF");
-    /**
-     * Color of the active cell (R, G, B, A) while mouse is over it.
-     */
-    private static final Color ACTIVE_COLOR_MOUSE_OVER = new Color("F9FF");
-    /**
-     * Color of the inactive cell (R, G, B, A)
-     */
-    private static final Color INACTIVE_COLOR = new Color("55F8");
-    /**
-     * Color of the inactive cell (R, G, B, A) while mouse is over it.
-     */
-    private static final Color INACTIVE_COLOR_MOUSE_OVER = new Color("77F8");
-    /**
-     * A placeholder variable to help in next generation computation. Indicates
-     * whether cell is going to survive within next generation.
-     */
-    public boolean survives;
-    /**
-     * Indicates whether cell is currently active
-     */
-    private boolean active;
-    /**
-     * Indicates whether mouse pointer is currently over this cell.
-     */
-    private boolean isMouseOver = false;
-
-    public Cell(final Point3D center) {
-        super(center);
-
-        createCellShape();
-
-        // enable receiving of mouse events
-        setMouseInteractionController(this);
-    }
-
-    private void createCellShape() {
-        final double halfSize = SIZE / 2f;
-
-        // define 4 points corresponding to cell borders
-        final Point3D p1 = new Point3D(-halfSize, 0, -halfSize);
-
-        final Point3D p2 = new Point3D(+halfSize, 0, -halfSize);
-
-        final Point3D p3 = new Point3D(+halfSize, 0, +halfSize);
-
-        final Point3D p4 = new Point3D(-halfSize, 0, +halfSize);
-
-        // connect 4 points with 2 polygons
-        addShape(new SolidPolygon(p1, p2, p3, computeCellColor()));
-        addShape(new SolidPolygon(p1, p4, p3, computeCellColor()));
-    }
-
-    /**
-     * Compute cell color depending if cell is active and if mouse is over the
-     * cell.
-     */
-    private Color computeCellColor() {
-        if (active)
-            if (isMouseOver)
-                return ACTIVE_COLOR_MOUSE_OVER;
-            else
-                return ACTIVE_COLOR;
-        else if (isMouseOver)
-            return INACTIVE_COLOR_MOUSE_OVER;
-        else
-            return INACTIVE_COLOR;
-    }
-
-    public boolean isActive() {
-        return active;
-    }
-
-    public void setActive(final boolean active) {
-        this.active = active;
-        updateColor();
-    }
-
-    @Override
-    public boolean mouseClicked() {
-        setActive(!isActive());
-        return true;
-    }
-
-    @Override
-    public boolean mouseEntered() {
-        setMouseOver(true);
-        return true;
-    }
-
-    @Override
-    public boolean mouseExited() {
-        setMouseOver(false);
-        return true;
-    }
-
-    private void setMouseOver(final boolean isMouseOver) {
-        this.isMouseOver = isMouseOver;
-        updateColor();
-    }
-
-    /**
-     * This method is called when cell status is changed to update its color
-     * too.
-     */
-    private void updateColor() {
-        setColor(computeCellColor());
-    }
-
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Main.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Main.java
deleted file mode 100644 (file)
index afc0e1c..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-package eu.svjatoslav.sixth.e3d.examples.life;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
-import eu.svjatoslav.sixth.e3d.geometry.Rectangle;
-import eu.svjatoslav.sixth.e3d.gui.Avatar;
-import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
-import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
-import eu.svjatoslav.sixth.e3d.gui.humaninput.WorldNavigationUserInputTracker;
-import eu.svjatoslav.sixth.e3d.math.Transform;
-import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
-import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.LineAppearance;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.Grid2D;
-
-import java.awt.event.KeyEvent;
-
-
-public class Main extends WorldNavigationUserInputTracker {
-
-    private static final Matrix MATRIX = new Matrix(
-            new Point3D() // position matrix in the center of the scene
-    );
-
-    public static void main(final String[] args) {
-        new Main().run();
-    }
-
-    /**
-     * Handle keyboard input.
-     */
-    @Override
-    public boolean keyPressed(final KeyEvent event, final ViewPanel viewPanel) {
-        switch (event.getKeyChar()) {
-            case ' ': // space key
-                MATRIX.evolve(false);
-                break;
-            case 10: // ENTER
-                MATRIX.evolve(true);
-                break;
-            case 'c': // reset matrix
-                MATRIX.clear();
-                break;
-            default:
-                return super.keyPressed(event, viewPanel);
-        }
-        return true;
-    }
-
-    private void run() {
-
-        // create application frame visible to the user
-        final ViewFrame viewFrame = new ViewFrame();
-
-        final ShapeCollection shapeCollection = viewFrame.getViewPanel()
-                .getRootShapeCollection();
-
-        // add matrix
-        shapeCollection.addShape(MATRIX);
-
-        // add wire-frame grid (optional)
-        shapeCollection.addShape(createGrid());
-
-        final ViewPanel viewPanel = viewFrame.getViewPanel();
-
-        setAvatarOrientation(viewPanel.getAvatar());
-
-        // enable receiving of keyboard events
-        viewPanel.getKeyboardFocusStack().pushFocusOwner(this);
-
-        // Done! World is built. So ensure screen is updated too.
-        viewPanel.repaintDuringNextViewUpdate();
-    }
-
-    /**
-     * Create pink wire-frame grid below (for decorative purposes).
-     */
-    private Grid2D createGrid() {
-        return new Grid2D(
-                new Transform(
-                        new Point3D( // Grid positioning:
-                                0, // center
-                                100, // below the main scene
-                                0), // center
-
-                        // Grid orientation:
-                        0, // no rotation along XZ axis
-                        Math.PI / 2), // face down
-
-                new Rectangle(800), // large enough, square grid
-
-                5, 5, // grid will be divided to 5x5 segments
-
-                new LineAppearance(3, // line thickness
-                        new Color("FF000050") // red and quite transparent
-                )
-        );
-    }
-
-    /**
-     * Set Avatar/Camera initial position in the world.
-     */
-    private void setAvatarOrientation(final Avatar avatar) {
-        avatar.setLocation(new Point3D(100, -50, -200));
-        avatar.setAngleXZ(0.2f);
-        avatar.setAngleYZ(-0.7f);
-    }
-
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Matrix.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Matrix.java
deleted file mode 100644 (file)
index ee7b0aa..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-package eu.svjatoslav.sixth.e3d.examples.life;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.SubShape;
-
-/**
- * This is our 2D game of life world. It contains 2D array of {@link Cell}'s.
- */
-class Matrix extends AbstractCompositeShape {
-
-    /**
-     * Empty space between cells.
-     */
-    private static final int BORDER = 5;
-
-    /**
-     * Matrix size X and Y. (Amount of cells.)
-     */
-    private static final int SIZE = 30;
-
-    /**
-     * Object marker in 3D scene. Allows to locate all stars from the scene.
-     */
-    private static final String GROUP_STARS = "stars";
-
-    /**
-     * Object marker in 3D scene. Allows to locate surface on the scene.
-     */
-    private static final String GROUP_SURFACE = "surface";
-
-    /**
-     * 2 dimensional matrix of cells
-     */
-    private final Cell[][] cells = new Cell[SIZE][];
-
-    public Matrix(final Point3D location) {
-        super(location);
-
-
-        for (int x = 0; x < SIZE; x++) {
-            cells[x] = new Cell[SIZE];
-
-            // init Y row
-            for (int z = 0; z < SIZE; z++) {
-                // create cell and register it
-                final Cell cell = new Cell(getCellLocation(x, z));
-                cells[x][z] = cell;
-                addShape(cell);
-            }
-        }
-
-        setGroupForUngrouped(GROUP_SURFACE);
-    }
-
-    /**
-     * Clear matrix.
-     */
-    public void clear() {
-
-        // mark every cell as inactive
-        for (int x = 0; x < SIZE; x++)
-            for (int y = 0; y < SIZE; y++)
-                cells[x][y].setActive(false);
-
-        // remove history stars
-        removeGroup(GROUP_STARS);
-    }
-
-    /**
-     * Compute survived cells based on the rules of Conway's Game of Life.
-     */
-    private void computeSurvivedCells() {
-
-        for (int y = 0; y < SIZE; y++)
-            for (int x = 0; x < SIZE; x++)
-                processCell(x, y);
-
-        for (int y = 0; y < SIZE; y++)
-            for (int x = 0; x < SIZE; x++)
-                cells[x][y].setActive(cells[x][y].survives);
-
-    }
-
-    private void processCell(int x, int y) {
-        int aliveNeighbours = countNeighbours(x, y);
-
-        if (cells[x][y].isActive()) {
-            cells[x][y].survives = ((aliveNeighbours == 2) || (aliveNeighbours == 3));
-        } else {
-            cells[x][y].survives = aliveNeighbours == 3;
-        }
-    }
-
-    private int countNeighbours(int x, int y) {
-        int result = 0;
-        for (int ny = y - 1; ny <= y + 1; ny++)
-            for (int nx = x - 1; nx <= x + 1; nx++)
-                if (isCellAlive(nx, ny)) result++;
-
-        if (isCellAlive(x, y)) result--;
-
-        return result;
-    }
-
-    private boolean isCellAlive(int x, int y) {
-        if (x < 0) return false;
-        if (x >= SIZE) return false;
-        if (y < 0) return false;
-        if (y >= SIZE) return false;
-        return cells[x][y].isActive();
-    }
-
-    /**
-     * Evolve matrix for one iteration
-     */
-    public void evolve(final boolean preserveHistory) {
-        if (preserveHistory)
-            markActiveCells();
-
-        shiftStarsUp();
-
-        computeSurvivedCells();
-    }
-
-    private Point3D getCellLocation(final int x, final int z) {
-        final int shift = -((SIZE / 2) * (Cell.SIZE + BORDER));
-
-        return new Point3D(
-                (x * (Cell.SIZE + BORDER)) + shift,
-                0,
-                (z * (Cell.SIZE + BORDER)) + shift);
-    }
-
-    /**
-     * Leave trail of active cells as stars above matrix.
-     */
-    private void markActiveCells() {
-        // mark survived cells
-        for (int x = 0; x < SIZE; x++)
-            for (int y = 0; y < SIZE; y++)
-                if (cells[x][y].isActive())
-                    addShape(new Star(getCellLocation(x, y)));
-
-        setGroupForUngrouped(GROUP_STARS);
-    }
-
-    /**
-     * Find all history tracking stars and shift them up.
-     */
-    private void shiftStarsUp() {
-
-        for (final SubShape subShape : getGroup(GROUP_STARS))
-            ((Star) subShape.getShape()).getLocation().translateY(-10);
-    }
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Star.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Star.java
deleted file mode 100644 (file)
index ad242d0..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-package eu.svjatoslav.sixth.e3d.examples.life;
-
-import eu.svjatoslav.sixth.e3d.geometry.Point3D;
-import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
-import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.GlowingPoint;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class Star extends GlowingPoint {
-    public static final int STAR_SIZE = 10;
-
-    public static final int UNIQUE_STARS_COUNT = 30;
-
-    private static final List<Color> uniqueStarColors = new ArrayList<>();
-
-    /**
-     * A little hack to save RAM. We are going to have potentially lot of stars.
-     * Instead of creating new individual texture for each star, Sixth 3D engine
-     * uses internal optimization and reuses existing star textures, if star with
-     * identical color already exists. To take advantage ot such optimization
-     * we create here limited set of precomputed star colors and later reuse them.
-     */
-    static {
-        for (int i = 0; i < UNIQUE_STARS_COUNT; i++)
-            uniqueStarColors.add(
-                    new Color(
-                            Math.random() + 0.5,
-                            Math.random() + 0.5,
-                            Math.random() + 0.5,
-                            255));
-    }
-
-    public Star(Point3D location) {
-        super(location,
-                STAR_SIZE,
-                uniqueStarColors.get((int) (Math.random() * uniqueStarColors.size())) // pick random pre-generated color
-        );
-    }
-
-}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Cell.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Cell.java
new file mode 100755 (executable)
index 0000000..4faa448
--- /dev/null
@@ -0,0 +1,131 @@
+package eu.svjatoslav.sixth.e3d.examples.life_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.MouseInteractionController;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.solidpolygon.SolidPolygon;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
+
+/**
+ * This class corresponds to a single cell within matrix.
+ */
+class Cell extends AbstractCompositeShape implements
+        MouseInteractionController {
+
+    /**
+     * cell visual size
+     */
+    static final int SIZE = 20;
+    /**
+     * Color of the active cell (R, G, B, A)
+     */
+    private static final Color ACTIVE_COLOR = new Color("A8FF");
+    /**
+     * Color of the active cell (R, G, B, A) while mouse is over it.
+     */
+    private static final Color ACTIVE_COLOR_MOUSE_OVER = new Color("F9FF");
+    /**
+     * Color of the inactive cell (R, G, B, A)
+     */
+    private static final Color INACTIVE_COLOR = new Color("55F8");
+    /**
+     * Color of the inactive cell (R, G, B, A) while mouse is over it.
+     */
+    private static final Color INACTIVE_COLOR_MOUSE_OVER = new Color("77F8");
+    /**
+     * A placeholder variable to help in next generation computation. Indicates
+     * whether cell is going to survive within next generation.
+     */
+    public boolean survives;
+    /**
+     * Indicates whether cell is currently active
+     */
+    private boolean active;
+    /**
+     * Indicates whether mouse pointer is currently over this cell.
+     */
+    private boolean isMouseOver = false;
+
+    public Cell(final Point3D center) {
+        super(center);
+
+        createCellShape();
+
+        // enable receiving of mouse events
+        setMouseInteractionController(this);
+    }
+
+    private void createCellShape() {
+        final double halfSize = SIZE / 2f;
+
+        // define 4 points corresponding to cell borders
+        final Point3D p1 = new Point3D(-halfSize, 0, -halfSize);
+
+        final Point3D p2 = new Point3D(+halfSize, 0, -halfSize);
+
+        final Point3D p3 = new Point3D(+halfSize, 0, +halfSize);
+
+        final Point3D p4 = new Point3D(-halfSize, 0, +halfSize);
+
+        // connect 4 points with 2 polygons
+        addShape(new SolidPolygon(p1, p2, p3, computeCellColor()));
+        addShape(new SolidPolygon(p1, p4, p3, computeCellColor()));
+    }
+
+    /**
+     * Compute cell color depending on if cell is active and if mouse is over the
+     * cell.
+     */
+    private Color computeCellColor() {
+        if (active)
+            if (isMouseOver)
+                return ACTIVE_COLOR_MOUSE_OVER;
+            else
+                return ACTIVE_COLOR;
+        else if (isMouseOver)
+            return INACTIVE_COLOR_MOUSE_OVER;
+        else
+            return INACTIVE_COLOR;
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void setActive(final boolean active) {
+        this.active = active;
+        updateColor();
+    }
+
+    @Override
+    public boolean mouseClicked(int button) {
+        setActive(!isActive());
+        return true;
+    }
+
+    @Override
+    public boolean mouseEntered() {
+        setMouseOver(true);
+        return true;
+    }
+
+    @Override
+    public boolean mouseExited() {
+        setMouseOver(false);
+        return true;
+    }
+
+    private void setMouseOver(final boolean isMouseOver) {
+        this.isMouseOver = isMouseOver;
+        updateColor();
+    }
+
+    /**
+     * This method is called when cell status is changed to update its color
+     * too.
+     */
+    private void updateColor() {
+        setColor(computeCellColor());
+    }
+
+}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Main.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Main.java
new file mode 100644 (file)
index 0000000..cf47e7f
--- /dev/null
@@ -0,0 +1,108 @@
+package eu.svjatoslav.sixth.e3d.examples.life_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.geometry.Rectangle;
+import eu.svjatoslav.sixth.e3d.gui.Avatar;
+import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
+import eu.svjatoslav.sixth.e3d.gui.ViewPanel;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.WorldNavigationUserInputTracker;
+import eu.svjatoslav.sixth.e3d.math.Transform;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.ShapeCollection;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.line.LineAppearance;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.wireframe.Grid2D;
+
+import java.awt.event.KeyEvent;
+
+
+public class Main extends WorldNavigationUserInputTracker {
+
+    private static final Matrix MATRIX = new Matrix(
+            new Point3D() // position matrix in the center of the scene
+    );
+
+    public static void main(final String[] args) {
+        new Main().run();
+    }
+
+    /**
+     * Handle keyboard input.
+     */
+    @Override
+    public boolean keyPressed(final KeyEvent event, final ViewPanel viewPanel) {
+        switch (event.getKeyChar()) {
+            case ' ': // space key
+                MATRIX.evolve(false);
+                break;
+            case 10: // ENTER
+                MATRIX.evolve(true);
+                break;
+            case 'c': // reset matrix
+                MATRIX.clear();
+                break;
+            default:
+                return super.keyPressed(event, viewPanel);
+        }
+        return true;
+    }
+
+    private void run() {
+
+        // create application frame visible to the user
+        final ViewFrame viewFrame = new ViewFrame();
+
+        final ShapeCollection shapeCollection = viewFrame.getViewPanel()
+                .getRootShapeCollection();
+
+        // add matrix
+        shapeCollection.addShape(MATRIX);
+
+        // add wire-frame grid (optional)
+        shapeCollection.addShape(createGrid());
+
+        final ViewPanel viewPanel = viewFrame.getViewPanel();
+
+        setAvatarOrientation(viewPanel.getAvatar());
+
+        // enable receiving of keyboard events
+        viewPanel.getKeyboardFocusStack().pushFocusOwner(this);
+
+        // Done! World is built. So ensure screen is updated too.
+        viewPanel.repaintDuringNextViewUpdate();
+    }
+
+    /**
+     * Create pink wire-frame grid below (for decorative purposes).
+     */
+    private Grid2D createGrid() {
+        return new Grid2D(
+                new Transform(
+                        new Point3D( // Grid positioning:
+                                0, // center
+                                100, // below the main scene
+                                0), // center
+
+                        // Grid orientation:
+                        0, // no rotation along XZ axis
+                        Math.PI / 2), // face down
+
+                new Rectangle(800), // large enough, square grid
+
+                5, 5, // grid will be divided to 5x5 segments
+
+                new LineAppearance(3, // line thickness
+                        new Color("FF000050") // red and quite transparent
+                )
+        );
+    }
+
+    /**
+     * Set Avatar/Camera initial position in the world.
+     */
+    private void setAvatarOrientation(final Avatar avatar) {
+        avatar.setLocation(new Point3D(100, -50, -200));
+        avatar.setAngleXZ(0.2f);
+        avatar.setAngleYZ(-0.7f);
+    }
+
+}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Matrix.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Matrix.java
new file mode 100644 (file)
index 0000000..8736b96
--- /dev/null
@@ -0,0 +1,156 @@
+package eu.svjatoslav.sixth.e3d.examples.life_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.AbstractCompositeShape;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.composite.base.SubShape;
+
+/**
+ * This is our 2D game of life world. It contains 2D array of {@link Cell}'s.
+ */
+class Matrix extends AbstractCompositeShape {
+
+    /**
+     * Empty space between cells.
+     */
+    private static final int BORDER = 5;
+
+    /**
+     * Matrix size X and Y. (Amount of cells.)
+     */
+    private static final int SIZE = 30;
+
+    /**
+     * Object marker in 3D scene. Allows to locate all stars from the scene.
+     */
+    private static final String GROUP_STARS = "stars";
+
+    /**
+     * Object marker in 3D scene. Allows to locate surface on the scene.
+     */
+    private static final String GROUP_SURFACE = "surface";
+
+    /**
+     * 2 dimensional matrix of cells
+     */
+    private final Cell[][] cells = new Cell[SIZE][];
+
+    public Matrix(final Point3D location) {
+        super(location);
+
+
+        for (int x = 0; x < SIZE; x++) {
+            cells[x] = new Cell[SIZE];
+
+            // init Y row
+            for (int z = 0; z < SIZE; z++) {
+                // create cell and register it
+                final Cell cell = new Cell(getCellLocation(x, z));
+                cells[x][z] = cell;
+                addShape(cell);
+            }
+        }
+
+        setGroupForUngrouped(GROUP_SURFACE);
+    }
+
+    /**
+     * Clear matrix.
+     */
+    public void clear() {
+
+        // mark every cell as inactive
+        for (int x = 0; x < SIZE; x++)
+            for (int y = 0; y < SIZE; y++)
+                cells[x][y].setActive(false);
+
+        // remove history stars
+        removeGroup(GROUP_STARS);
+    }
+
+    /**
+     * Compute survived cells based on the rules of Conway's Game of Life.
+     */
+    private void computeSurvivedCells() {
+
+        for (int y = 0; y < SIZE; y++)
+            for (int x = 0; x < SIZE; x++)
+                processCell(x, y);
+
+        for (int y = 0; y < SIZE; y++)
+            for (int x = 0; x < SIZE; x++)
+                cells[x][y].setActive(cells[x][y].survives);
+
+    }
+
+    private void processCell(int x, int y) {
+        int aliveNeighbours = countNeighbours(x, y);
+
+        if (cells[x][y].isActive()) {
+            cells[x][y].survives = ((aliveNeighbours == 2) || (aliveNeighbours == 3));
+        } else {
+            cells[x][y].survives = aliveNeighbours == 3;
+        }
+    }
+
+    private int countNeighbours(int x, int y) {
+        int result = 0;
+        for (int ny = y - 1; ny <= y + 1; ny++)
+            for (int nx = x - 1; nx <= x + 1; nx++)
+                if (isCellAlive(nx, ny)) result++;
+
+        if (isCellAlive(x, y)) result--;
+
+        return result;
+    }
+
+    private boolean isCellAlive(int x, int y) {
+        if (x < 0) return false;
+        if (x >= SIZE) return false;
+        if (y < 0) return false;
+        if (y >= SIZE) return false;
+        return cells[x][y].isActive();
+    }
+
+    /**
+     * Evolve matrix for one iteration
+     */
+    public void evolve(final boolean preserveHistory) {
+        if (preserveHistory)
+            markActiveCells();
+
+        shiftStarsUp();
+
+        computeSurvivedCells();
+    }
+
+    private Point3D getCellLocation(final int x, final int z) {
+        final int shift = -((SIZE / 2) * (Cell.SIZE + BORDER));
+
+        return new Point3D(
+                (x * (Cell.SIZE + BORDER)) + shift,
+                0,
+                (z * (Cell.SIZE + BORDER)) + shift);
+    }
+
+    /**
+     * Leave trail of active cells as stars above matrix.
+     */
+    private void markActiveCells() {
+        // mark survived cells
+        for (int x = 0; x < SIZE; x++)
+            for (int y = 0; y < SIZE; y++)
+                if (cells[x][y].isActive())
+                    addShape(new Star(getCellLocation(x, y)));
+
+        setGroupForUngrouped(GROUP_STARS);
+    }
+
+    /**
+     * Find all history tracking stars and shift them up.
+     */
+    private void shiftStarsUp() {
+
+        for (final SubShape subShape : getGroup(GROUP_STARS))
+            ((Star) subShape.getShape()).getLocation().translateY(-10);
+    }
+}
diff --git a/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Star.java b/src/main/java/eu/svjatoslav/sixth/e3d/examples/life_demo/Star.java
new file mode 100644 (file)
index 0000000..6f5edaa
--- /dev/null
@@ -0,0 +1,41 @@
+package eu.svjatoslav.sixth.e3d.examples.life_demo;
+
+import eu.svjatoslav.sixth.e3d.geometry.Point3D;
+import eu.svjatoslav.sixth.e3d.renderer.raster.Color;
+import eu.svjatoslav.sixth.e3d.renderer.raster.shapes.basic.GlowingPoint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class Star extends GlowingPoint {
+    public static final int STAR_SIZE = 10;
+
+    public static final int UNIQUE_STARS_COUNT = 30;
+
+    private static final List<Color> uniqueStarColors = new ArrayList<>();
+
+    /*
+     * A little hack to save RAM. We are going to have potentially lot of stars.
+     * Instead of creating new individual texture for each star, Sixth 3D engine
+     * uses internal optimization and reuses existing star textures, if star with
+     * identical color already exists. To take advantage ot such optimization
+     * we create here limited set of precomputed star colors and later reuse them.
+     */
+    static {
+        for (int i = 0; i < UNIQUE_STARS_COUNT; i++)
+            uniqueStarColors.add(
+                    new Color(
+                            Math.random() + 0.5,
+                            Math.random() + 0.5,
+                            Math.random() + 0.5,
+                            255));
+    }
+
+    public Star(Point3D location) {
+        super(location,
+                STAR_SIZE,
+                uniqueStarColors.get((int) (Math.random() * uniqueStarColors.size())) // pick random pre-generated color
+        );
+    }
+
+}
index 057b511..5931849 100755 (executable)
@@ -1,5 +1,7 @@
 #!/bin/bash
-cd "${0%/*}"; if [ "$1" != "T" ]; then gnome-terminal -e "'$0' T"; exit; fi;
+
+cd "${0%/*}"; if [ "$1" != "T" ]; then gnome-terminal -- "$0" T; exit; fi;
+
 
 cd ..
 
diff --git a/tools/debug b/tools/debug
deleted file mode 100755 (executable)
index 5640906..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#!/bin/bash
-
-if [ "$1" != "T" ]; then gnome-terminal -e "'$0' T"; exit; fi
-
-#
-# This is a helper bash script that starts current Java project in debug mode
-# with JRebel attached. It also opens its own terminal window, so you can run
-# this script by simply clicking on it in file navigator.
-#
-#
-# Script assumes:
-#
-#    + GNU OS 
-#    + Gnome workspace
-#    + JRebel is installed in /opt/jrebel
-#
-
-
-cd "${0%/*}"
-cd ..
-
-
-while true; do
-
-    # clear screen
-    printf "\033c"
-
-    # enable debugging
-    export DEBUG_OPTIONS="-Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8000,server=y,suspend=n"
-
-    # enable JRebel
-    export REBEL_BASE="$HOME/.jrebel"
-    export JREBEL_OPTS="-agentpath:/opt/jrebel/libjrebel64.so -Drebel.project.path=`pwd`"
-
-    # enable LWJGL native libraries
-    export LWJGL_OPTS="-Djava.library.path=target/natives"
-    
-    # define Maven options
-    export MAVEN_OPTS="-Xmx4000m $DEBUG_OPTIONS $JREBEL_OPTS $LWJGL_OPTS"
-    
-    mvn compile exec:java -Dexec.mainClass="eu.svjatoslav.sixth.e3d.examples.launcher.Main"
-    
-    echo "press ENTER to reload application"
-    read
-
-done
index de9bae5..304bf94 100755 (executable)
@@ -1,18 +1,54 @@
 #!/bin/bash
 
-#
-# This is a helper bash script that starts IntelliJ with the current project.
-# Script is written is such a way that you can simply click on it in file
-# navigator to run it.
-#
-#
-# Script assumes:
-#
-#    + GNU operating system
-#    + IntelliJ is installed and commandline launcher "idea" is enabled.
-#
+# This script launches IntelliJ IDEA with the current project
+# directory. The script is designed to be run by double-clicking it in
+# the GNOME Nautilus file manager.
+
+# First, we change the current working directory to the directory of
+# the script.
+
+# "${0%/*}" gives us the path of the script itself, without the
+# script's filename.
+
+# This command basically tells the system "change the current
+# directory to the directory containing this script".
 
 cd "${0%/*}"
+
+# Then, we move up one directory level.
+# The ".." tells the system to go to the parent directory of the current directory.
+# This is done because we assume that the project directory is one level up from the script.
 cd ..
 
-setsid idea . &>/dev/null
+# Now, we use the 'setsid' command to start a new session and run
+# IntelliJ IDEA in the background. 'setsid' is a UNIX command that
+# runs a program in a new session.
+
+# The command 'idea .' opens IntelliJ IDEA with the current directory
+# as the project directory.  The '&' at the end is a UNIX command that
+# runs the process in the background.  The '> /dev/null' part tells
+# the system to redirect all output (both stdout and stderr, denoted
+# by '&') that would normally go to the terminal to go to /dev/null
+# instead, which is a special file that discards all data written to
+# it.
+
+setsid idea . &>/dev/null &
+
+# The 'disown' command is a shell built-in that removes a shell job
+# from the shell's active list. Therefore, the shell will not send a
+# SIGHUP to this particular job when the shell session is terminated.
+
+# '-h' option specifies that if the shell receives a SIGHUP, it also
+# doesn't send a SIGHUP to the job.
+
+# '$!' is a shell special parameter that expands to the process ID of
+# the most recent background job.
+disown -h $!
+
+
+sleep 2
+
+# Finally, we use the 'exit' command to terminate the shell script.
+# This command tells the system to close the terminal window after
+# IntelliJ IDEA has been opened.
+exit
index 7442ab6..49d31e4 100755 (executable)
@@ -1,5 +1,5 @@
 #!/bin/bash
-cd "${0%/*}"; if [ "$1" != "T" ]; then gnome-terminal -e "'$0' T"; exit; fi;
+cd "${0%/*}"; if [ "$1" != "T" ]; then gnome-terminal -- "$0" T; exit; fi;
 
 cd ..