<html lang="en">
<head>
<title>Sixth 3D engine demos</title>
-<!-- 2017-07-07 Fri 13:12 -->
+<!-- 2017-07-15 Sat 11:04 -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="generator" content="Org-mode">
<div id="outline-container-sec-1" class="outline-2">
-<h2 id="sec-1"><span class="section-number-2">1</span> Description</h2>
+<h2 id="sec-1"><span class="section-number-2">1</span> Overview</h2>
<div class="outline-text-2" id="text-1">
<p>
-Goal of this project is to show off capabilities of <a href="http://www2.svjatoslav.eu/gitbrowse/sixth-3d/doc/index.html">Sixth 3D</a>
-engine. Also to show examples of its usage.
+Goal of this project is to show off capabilities and API usage of
+<a href="http://www2.svjatoslav.eu/gitbrowse/sixth-3d/doc/index.html">Sixth 3D</a> engine.
</p>
+<p>
+All sample scenes below are rendered at interactive framerates.
+</p>
+</div>
+</div>
+<div id="outline-container-sec-2" class="outline-2">
+<h2 id="sec-2"><span class="section-number-2">2</span> Navigating in space</h2>
+<div class="outline-text-2" id="text-2">
+<table class="table table-striped table-bordered table-hover table-condensed">
+
+
+<colgroup>
+<col class="left">
+
+<col class="left">
+</colgroup>
+<thead>
+<tr>
+<th scope="col" class="text-left">key</th>
+<th scope="col" class="text-left">result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="text-left">cursor keys</td>
+<td class="text-left">move: left, right, forward, backward</td>
+</tr>
+
+<tr>
+<td class="text-left">mouse scroll wheel</td>
+<td class="text-left">move: up, down</td>
+</tr>
+
+<tr>
+<td class="text-left">dragging with mouse</td>
+<td class="text-left">look around</td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+
+<div id="outline-container-sec-3" class="outline-2">
+<h2 id="sec-3"><span class="section-number-2">3</span> Samples</h2>
+<div class="outline-text-2" id="text-3">
+</div><div id="outline-container-sec-3-1" class="outline-3">
+<h3 id="sec-3-1"><span class="section-number-3">3.1</span> Raytracing through voxels</h3>
+<div class="outline-text-3" id="text-3-1">
<figure>
-<p><a href="screenshots/index.html"><img src="screenshots.png" class="img-responsive" alt="screenshots.png"></a>
+<p><img src="screenshots/raytracing fractal in voxel polygon hybrid scene.png" class="img-responsive" alt="raytracing fractal in voxel polygon hybrid scene.png">
</p>
</figure>
<p>
-Sample scenes rendered at interactive framerates by Sixth 3D engine.
+Test scene that is generated simultaneously using:
+</p>
+<ul class="org-ul">
+<li>conventional polygons
+<ul class="org-ul">
+<li>for realtime navigation, and
+</li>
+</ul>
+</li>
+<li>voxels
+<ul class="org-ul">
+<li>for on-demand raytracing
+</li>
+</ul>
+</li>
+</ul>
+
+<p>
+Instead of storing voxels in dumb [X * Y * Z] array, dynamically
+partitioned <a href="https://en.wikipedia.org/wiki/Octree">octree</a> is used to compress data. Press "r" key anywhere in
+the scene to raytrace current view through compressed voxel
+datastructure.
</p>
</div>
</div>
+
+<div id="outline-container-sec-3-2" class="outline-3">
+<h3 id="sec-3-2"><span class="section-number-3">3.2</span> Conway's Game of Life</h3>
+<div class="outline-text-3" id="text-3-2">
+<p>
+The Game of Life, also known simply as Life, is a cellular automaton
+devised by the British mathematician John Horton Conway in 1970.
+</p>
+
+<ul class="org-ul">
+<li><a href="https://en.wikipedia.org/wiki/Conway's_Game_of_Life">https://en.wikipedia.org/wiki/Conway's_Game_of_Life</a>
+<ul class="org-ul">
+<li>Game rules:
+<ul class="org-ul">
+<li>2 cell states: alive / dead
+</li>
+<li>Each cell sees 8 neighboring cells.
+</li>
+<li>If alive cell neighbors count is 2 or 3, then cell survives,
+otherwise it dies.
+</li>
+<li>Dead cell becomes alive if neighbors count is exactly 3.
+</li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+
+
+<figure>
+<p><img src="screenshots/life.png" class="img-responsive" alt="life.png">
+</p>
+</figure>
+
+<p>
+Current application projects 2D game grid/matrix onto three
+dimensional space. Extra dimension (height) is used to visualize
+history (previous iterations) using glowing dots suspended in space.
+</p>
+
+<p>
+Usage:
+</p>
+<table class="table table-striped table-bordered table-hover table-condensed">
+
+
+<colgroup>
+<col class="left">
+
+<col class="left">
+</colgroup>
+<thead>
+<tr>
+<th scope="col" class="text-left">key</th>
+<th scope="col" class="text-left">result</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td class="text-left">mouse click on the cell (cell)</td>
+<td class="text-left">toggles cell state</td>
+</tr>
+
+<tr>
+<td class="text-left"><space></td>
+<td class="text-left">next iteration</td>
+</tr>
+
+<tr>
+<td class="text-left">ENTER</td>
+<td class="text-left">next iteeration with the history</td>
+</tr>
+
+<tr>
+<td class="text-left">"c"</td>
+<td class="text-left">clear the matrix</td>
+</tr>
+</tbody>
+</table>
+</div>
+</div>
+
+<div id="outline-container-sec-3-3" class="outline-3">
+<h3 id="sec-3-3"><span class="section-number-3">3.3</span> Text editors</h3>
+<div class="outline-text-3" id="text-3-3">
+
+<figure>
+<p><img src="screenshots/text editors.png" class="img-responsive" alt="text editors.png">
+</p>
+</figure>
+
+<p>
+Initial test for creating user interfaces in 3D and:
+</p>
+<ul class="org-ul">
+<li>window focus handling
+</li>
+<li>picking objecs using mouse
+</li>
+<li>redirecting keyboard input to focused window
+</li>
+</ul>
+
+
+<p>
+Window focus acts like a stack.
+</p>
+
+<p>
+When window is clicked with the mouse, previously focused window (if
+any) is pushed to the focus stack and new window receives focus. Red
+frame appears around the window to indicate this.
+</p>
+
+<p>
+When ESC key is pressed, window focus is returned to previous window
+(if any).
+</p>
+
+<p>
+When any window is focused, all keyboard input is redirected to that
+window, including cursor keys. To be able to navigate around the world
+again, window must be unfocused first using ESC key.
+</p>
+
+
+<ul class="org-ul">
+<li>TODO:
+<ul class="org-ul">
+<li>Improve focus handling:
+<ul class="org-ul">
+<li>Perhaps add shortcut to navigate world without exiting entire
+stack of focus.
+</li>
+<li>Possibility to retain and reuse recently focused elements.
+</li>
+<li>Store user location in the world and view direction with the
+focused window. So that when returning focus to far away object,
+user is redirected also to proper location in the world.
+</li>
+</ul>
+</li>
+<li>Possibility to store recently visited locations in the world and
+return to them.
+</li>
+</ul>
+</li>
+</ul>
+</div>
+</div>
+<div id="outline-container-sec-3-4" class="outline-3">
+<h3 id="sec-3-4"><span class="section-number-3">3.4</span> Mathematical formulas</h3>
+<div class="outline-text-3" id="text-3-4">
+
+<figure>
+<p><img src="screenshots/mathematical formulas.png" class="img-responsive" alt="mathematical formulas.png">
+</p>
+</figure>
+
+<ul class="org-ul">
+<li>TODO: instead of projecting 2D visualizations onto 3D space,
+visualize some formula using all 3 dimensions avaliable.
+</li>
+</ul>
+</div>
+</div>
+<div id="outline-container-sec-3-5" class="outline-3">
+<h3 id="sec-3-5"><span class="section-number-3">3.5</span> Sinus heightmaps and sphere</h3>
+<div class="outline-text-3" id="text-3-5">
+
+<figure>
+<p><img src="screenshots/sinus heightmaps and sphere.png" class="img-responsive" alt="sinus heightmaps and sphere.png">
+</p>
+</figure>
+
+<p>
+Simple test scene. Easy to implement and looks nice.
+</p>
+</div>
+</div>
+</div>
</div><div class="col-md-3"><nav id="table-of-contents">
<div id="text-table-of-contents" class="bs-docs-sidebar">
<ul class="nav">
-<li><a href="#sec-1">1. Description</a></li>
+<li><a href="#sec-1">1. Overview</a></li>
+<li><a href="#sec-2">2. Navigating in space</a></li>
+<li><a href="#sec-3">3. Samples</a>
+<ul class="nav">
+<li><a href="#sec-3-1">3.1. Raytracing through voxels</a></li>
+<li><a href="#sec-3-2">3.2. Conway's Game of Life</a></li>
+<li><a href="#sec-3-3">3.3. Text editors</a></li>
+<li><a href="#sec-3-4">3.4. Mathematical formulas</a></li>
+<li><a href="#sec-3-5">3.5. Sinus heightmaps and sphere</a></li>
+</ul>
+</li>
</ul>
</div>
</nav>
</div></div></div>
<footer id="postamble" class="">
<div><p class="author">Author: Svjatoslav Agejenko</p>
-<p class="date">Created: 2017-07-07 Fri 13:12</p>
+<p class="date">Created: 2017-07-15 Sat 11:04</p>
<p class="creator"><a href="http://www.gnu.org/software/emacs/">Emacs</a> 25.1.1 (<a href="http://orgmode.org">Org-mode</a> 8.2.10)</p>
</div>
</footer>
#+HTML_HEAD: pre {background-color: #111; color: #ccc;}
#+HTML_HEAD: </style>
-* Description
-Goal of this project is to show off capabilities of [[http://www2.svjatoslav.eu/gitbrowse/sixth-3d/doc/index.html][Sixth 3D]]
-engine. Also to show examples of its usage.
+* Overview
+Goal of this project is to show off capabilities and API usage of
+[[http://www2.svjatoslav.eu/gitbrowse/sixth-3d/doc/index.html][Sixth 3D]] engine.
-[[file:screenshots/index.html][file:screenshots.png]]
+All sample scenes below are rendered at interactive framerates.
+* Navigating in space
+| key | result |
+|--------------------------------+--------------------------------------|
+| cursor keys | move: left, right, forward, backward |
+| mouse scroll wheel | move: up, down |
+| dragging with mouse | look around |
-Sample scenes rendered at interactive framerates by Sixth 3D engine.
+* Samples
+** Raytracing through voxels
+[[file:screenshots/raytracing fractal in voxel polygon hybrid scene.png]]
+
+Test scene that is generated simultaneously using:
++ conventional polygons
+ + for realtime navigation, and
++ voxels
+ + for on-demand raytracing
+
+Instead of storing voxels in dumb [X * Y * Z] array, dynamically
+partitioned [[https://en.wikipedia.org/wiki/Octree][octree]] is used to compress data. Press "r" key anywhere in
+the scene to raytrace current view through compressed voxel
+datastructure.
+
+** Conway's Game of Life
+The Game of Life, also known simply as Life, is a cellular automaton
+devised by the British mathematician John Horton Conway in 1970.
+
++ https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life
+ + Game rules:
+ + 2 cell states: alive / dead
+ + Each cell sees 8 neighboring cells.
+ + If alive cell neighbors count is 2 or 3, then cell survives,
+ otherwise it dies.
+ + Dead cell becomes alive if neighbors count is exactly 3.
+
+[[file:screenshots/life.png]]
+
+Current application projects 2D game grid/matrix onto three
+dimensional space. Extra dimension (height) is used to visualize
+history (previous iterations) using glowing dots suspended in space.
+
+Usage:
+| key | result |
+|--------------------------------+--------------------------------------|
+| mouse click on the cell (cell) | toggles cell state |
+| <space> | next iteration |
+| ENTER | next iteeration with the history |
+| "c" | clear the matrix |
+
+** Text editors
+[[file:screenshots/text editors.png]]
+
+Initial test for creating user interfaces in 3D and:
++ window focus handling
++ picking objecs using mouse
++ redirecting keyboard input to focused window
+
+
+Window focus acts like a stack.
+
+When window is clicked with the mouse, previously focused window (if
+any) is pushed to the focus stack and new window receives focus. Red
+frame appears around the window to indicate this.
+
+When ESC key is pressed, window focus is returned to previous window
+(if any).
+
+When any window is focused, all keyboard input is redirected to that
+window, including cursor keys. To be able to navigate around the world
+again, window must be unfocused first using ESC key.
+
+
++ TODO:
+ + Improve focus handling:
+ + Perhaps add shortcut to navigate world without exiting entire
+ stack of focus.
+ + Possibility to retain and reuse recently focused elements.
+ + Store user location in the world and view direction with the
+ focused window. So that when returning focus to far away object,
+ user is redirected also to proper location in the world.
+ + Possibility to store recently visited locations in the world and
+ return to them.
+** Mathematical formulas
+[[file:screenshots/mathematical formulas.png]]
+
++ TODO: instead of projecting 2D visualizations onto 3D space,
+ visualize some formula using all 3 dimensions avaliable.
+** Sinus heightmaps and sphere
+[[file:screenshots/sinus heightmaps and sphere.png]]
+
+Simple test scene. Easy to implement and looks nice.
+++ /dev/null
-<HTML>
-<HEAD>
- <meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8"/>
-</HEAD>
-<BODY bgcolor="#000000" alink="#50ffff" link="#50ffff" vlink="#ff50ff" text="#ffffff">
-<!-- DirListGen -->
-<!-- Directory Listing Generator by Svjatoslav Agejenko. E-mail: svjatoslav@svjatoslav.eu, homepage: http://svjatoslav.eu -->
-<font color="#ffffff">
-<CENTER><H1>Gallery</H1></CENTER>
-<CENTER><H2></H2></CENTER>
-<TABLE>
-
-<TR><TD><br></TD></TR>
-</TABLE>
-<div style="float:left; margin: 10px;"><a href="another%20test%20scene.png">
-<img border="0" src=".thumbnails/another%20test%20scene%20%2862C8D31D%29.jpeg"/></a><br/>
-<b>another test scene</b><br/>(<a href="another test scene.png">1680x1026</a>, <a href=".thumbnails/another%20test%20scene%20%285362752B%29.jpeg">840x513</a>)
-</div><div style="float:left; margin: 10px;"><a href="mathematical%20formulas.png">
-<img border="0" src=".thumbnails/mathematical%20formulas%20%287454DC19%29.jpeg"/></a><br/>
-<b>mathematical formulas</b><br/>(<a href="mathematical formulas.png">1680x1026</a>, <a href=".thumbnails/mathematical%20formulas%20%2882926553%29.jpeg">840x513</a>)
-</div><div style="float:left; margin: 10px;"><a href="raytracing%20fractal%20in%20voxel%20polygon%20hybrid%20scene.png">
-<img border="0" src=".thumbnails/raytracing%20fractal%20in%20voxel%20polygon%20hybrid%20scene%20%28534B3488%29.jpeg"/></a><br/>
-<b>raytracing fractal in voxel polygon hybrid scene</b><br/>(<a href="raytracing fractal in voxel polygon hybrid scene.png">1680x1026</a>, <a href=".thumbnails/raytracing%20fractal%20in%20voxel%20polygon%20hybrid%20scene%20%281F22E82D%29.jpeg">840x513</a>)
-</div><div style="float:left; margin: 10px;"><a href="text%20editors.png">
-<img border="0" src=".thumbnails/text%20editors%20%28C0263A2%29.jpeg"/></a><br/>
-<b>text editors</b><br/>(<a href="text editors.png">1672x977</a>, <a href=".thumbnails/text%20editors%20%28CBB27271%29.jpeg">836x488</a>)
-</div></font></BODY></HTML>
<dependency>
<groupId>eu.svjatoslav</groupId>
<artifactId>sixth-3d</artifactId>
- <version>1.0</version>
+ <version>1.1</version>
</dependency>
<dependency>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.8.1" level="project" />
- <orderEntry type="library" name="Maven: eu.svjatoslav:sixth-3d:1.0" level="project" />
+ <orderEntry type="library" name="Maven: eu.svjatoslav:sixth-3d:1.1" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: eu.svjatoslav:javainspect:1.5" level="project" />
<orderEntry type="library" scope="TEST" name="Maven: eu.svjatoslav:svjatoslavcommons:1.5" level="project" />
</component>
public MenuPanel() {
- final JLabel lblNewLabel = new JLabel("Choose an example to launch.");
+ final JLabel chooseExample = new JLabel("Choose an example to launch.");
- final JButton btnNewButton = new JButton("Demo 1");
- btnNewButton.addActionListener(e -> {
- });
- Action action = new SwingAction();
- btnNewButton.setAction(action);
+ final JButton showTextEditors = new JButton(new ShowTextEditors());
+ final JButton showSinusMap = new JButton(new ShowSinusMap());
+ final JButton showRain = new JButton(new ShowRain());
+ final JButton showPointCloud = new JButton(new ShowPointcloud());
+ final JButton showMathGraphs = new JButton(new ShowMathGraphs());
+ final JButton showOctree = new JButton(new ShowOctree());
- final JButton btnNewButton_1 = new JButton("Demo 2");
- Action action_1 = new SwingAction_1();
- btnNewButton_1.setAction(action_1);
-
- final JButton button = new JButton("New button");
- Action action_2 = new SwingAction_2();
- button.setAction(action_2);
-
- final JButton btnNewButton_2 = new JButton("New button");
- Action action_3 = new SwingAction_3();
- btnNewButton_2.setAction(action_3);
-
- final JButton btnNewButton_3 = new JButton("New button");
- Action action_4 = new SwingAction_4();
- btnNewButton_3.setAction(action_4);
-
- final JButton btnNewButton_4 = new JButton("New button");
- Action action_5 = new SwingAction_5();
- btnNewButton_4.setAction(action_5);
final GroupLayout groupLayout = new GroupLayout(this);
groupLayout
.setHorizontalGroup(groupLayout
groupLayout
.createSequentialGroup()
.addComponent(
- lblNewLabel,
+ chooseExample,
GroupLayout.PREFERRED_SIZE,
426,
GroupLayout.PREFERRED_SIZE)
.createParallelGroup(
Alignment.TRAILING)
.addComponent(
- btnNewButton_4,
+ showOctree,
Alignment.LEADING,
GroupLayout.DEFAULT_SIZE,
331,
Short.MAX_VALUE)
.addComponent(
- btnNewButton_3,
+ showMathGraphs,
Alignment.LEADING,
GroupLayout.DEFAULT_SIZE,
331,
Short.MAX_VALUE)
.addComponent(
- btnNewButton_2,
+ showPointCloud,
Alignment.LEADING,
GroupLayout.DEFAULT_SIZE,
331,
Short.MAX_VALUE)
.addComponent(
- button,
+ showRain,
Alignment.LEADING,
GroupLayout.DEFAULT_SIZE,
331,
Short.MAX_VALUE)
.addComponent(
- btnNewButton_1,
+ showSinusMap,
Alignment.LEADING,
GroupLayout.DEFAULT_SIZE,
GroupLayout.DEFAULT_SIZE,
Short.MAX_VALUE)
.addComponent(
- btnNewButton,
+ showTextEditors,
GroupLayout.DEFAULT_SIZE,
331,
Short.MAX_VALUE))
groupLayout
.createSequentialGroup()
.addGap(7)
- .addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE,
+ .addComponent(chooseExample, GroupLayout.PREFERRED_SIZE,
58, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(btnNewButton)
+ .addComponent(showTextEditors)
.addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(btnNewButton_1)
+ .addComponent(showSinusMap)
.addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(button)
+ .addComponent(showRain)
.addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(btnNewButton_2)
+ .addComponent(showPointCloud)
.addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(btnNewButton_3)
+ .addComponent(showMathGraphs)
.addPreferredGap(ComponentPlacement.RELATED)
- .addComponent(btnNewButton_4)
+ .addComponent(showOctree)
.addContainerGap(137, Short.MAX_VALUE)));
setLayout(groupLayout);
}
- private class SwingAction extends AbstractAction {
+ private class ShowTextEditors extends AbstractAction {
private static final long serialVersionUID = 5197962166765841015L;
- public SwingAction() {
+ public ShowTextEditors() {
putValue(NAME, "Text editors");
- putValue(SHORT_DESCRIPTION, "Some short description");
}
@Override
}
}
- private class SwingAction_1 extends AbstractAction {
+ private class ShowSinusMap extends AbstractAction {
private static final long serialVersionUID = -896479509963403828L;
- public SwingAction_1() {
+ public ShowSinusMap() {
putValue(NAME, "Wireframe sphere and ploygon landscape");
- putValue(SHORT_DESCRIPTION, "Some short description");
}
@Override
public void actionPerformed(final ActionEvent e) {
SphereDemo.main(null);
-
}
}
- private class SwingAction_2 extends AbstractAction {
+ private class ShowRain extends AbstractAction {
private static final long serialVersionUID = 8566009849873897321L;
- public SwingAction_2() {
+ public ShowRain() {
putValue(NAME, "Raining numbers");
- putValue(SHORT_DESCRIPTION, "Some short description");
}
@Override
}
}
- private class SwingAction_3 extends AbstractAction {
+ private class ShowPointcloud extends AbstractAction {
private static final long serialVersionUID = -5369105936409884389L;
- public SwingAction_3() {
+ public ShowPointcloud() {
putValue(NAME, "Pointcloud galaxy");
- putValue(SHORT_DESCRIPTION, "Some short description");
}
@Override
}
}
- private class SwingAction_4 extends AbstractAction {
+ private class ShowMathGraphs extends AbstractAction {
private static final long serialVersionUID = -8486796142555764460L;
- public SwingAction_4() {
+ public ShowMathGraphs() {
putValue(NAME, "Mathematical graphs");
- putValue(SHORT_DESCRIPTION, "Some short description");
}
@Override
}
}
- private class SwingAction_5 extends AbstractAction {
+ private class ShowOctree extends AbstractAction {
private static final long serialVersionUID = -6210703594848004946L;
- public SwingAction_5() {
+ public ShowOctree() {
putValue(NAME, "Volumetric Octree");
- putValue(SHORT_DESCRIPTION, "Some short description");
}
@Override
--- /dev/null
+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.
+ */
+public class Cell extends AbstractCompositeShape implements
+ MouseInteractionController {
+
+ /**
+ * cell visual size
+ */
+ public 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("55F5");
+ /**
+ * Color of the inactive cell (R, G, B, A) while mouse is over it.
+ */
+ private static final Color INACTIVE_COLOR_MOUSE_OVER = new Color("77F7");
+ /**
+ * 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 / 2;
+
+ // 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 void mouseClicked() {
+ setActive(!isActive());
+ }
+
+ @Override
+ public void mouseEntered() {
+ setMouseOver(true);
+ }
+
+ @Override
+ public void mouseExited() {
+ setMouseOver(false);
+ }
+
+ 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());
+ }
+
+}
--- /dev/null
+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.geometry.Transform;
+import eu.svjatoslav.sixth.e3d.gui.Avatar;
+import eu.svjatoslav.sixth.e3d.gui.ViewContext;
+import eu.svjatoslav.sixth.e3d.gui.ViewFrame;
+import eu.svjatoslav.sixth.e3d.gui.humaninput.WorldNavigationTracker;
+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;
+
+
+class Main extends WorldNavigationTracker {
+
+ 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 void keyPressed(final KeyEvent event, final ViewContext viewContext) {
+ 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:
+ super.keyPressed(event, viewContext);
+ }
+ }
+
+ private void run() {
+
+ // create application frame visible to the user
+ final ViewFrame viewFrame = new ViewFrame();
+
+ final ShapeCollection shapeCollection = viewFrame.getView()
+ .getContext().getRootShapeCollection();
+
+ // add matrix
+ shapeCollection.addShape(MATRIX);
+
+ // add wireframe grid (optional)
+ shapeCollection.addShape(createGrid());
+
+ final ViewContext context = viewFrame.getView().getContext();
+
+ setAvatarOrientation(context.getAvatar());
+
+ // enable receiving of keyboard events
+ context.getKeyboardFocusTracker().setFocusOwner(this);
+
+ // Done! World is built. So ensure screen is updated too.
+ context.getView().repaintDuringNextViewUpdate();
+ }
+
+ /**
+ * Create pink wireframe 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);
+ }
+
+}
--- /dev/null
+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);
+ }
+}
--- /dev/null
+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;
+
+public 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
+ );
+ }
+
+}