Updated documentation. Added game of life. Refactoring launcher panel.
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 15 Jul 2017 09:29:31 +0000 (11:29 +0200)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Sat, 15 Jul 2017 09:29:31 +0000 (11:29 +0200)
22 files changed:
doc/index.html
doc/index.org
doc/screenshots/.thumbnails/another test scene (5362752B).jpeg [deleted file]
doc/screenshots/.thumbnails/another test scene (62C8D31D).jpeg [deleted file]
doc/screenshots/.thumbnails/mathematical formulas (7454DC19).jpeg [deleted file]
doc/screenshots/.thumbnails/mathematical formulas (82926553).jpeg [deleted file]
doc/screenshots/.thumbnails/metadata_6.dat [deleted file]
doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (1F22E82D).jpeg [deleted file]
doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (534B3488).jpeg [deleted file]
doc/screenshots/.thumbnails/text editors (C0263A2).jpeg [deleted file]
doc/screenshots/.thumbnails/text editors (CBB27271).jpeg [deleted file]
doc/screenshots/another test scene.png [deleted file]
doc/screenshots/index.html [deleted file]
doc/screenshots/life.png [new file with mode: 0644]
doc/screenshots/sinus heightmaps and sphere.png [new file with mode: 0644]
pom.xml
sixth-3d-demos.iml
src/main/java/eu/svjatoslav/sixth/e3d/examples/launcher/MenuPanel.java
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Cell.java [new file with mode: 0755]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Main.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Matrix.java [new file with mode: 0644]
src/main/java/eu/svjatoslav/sixth/e3d/examples/life/Star.java [new file with mode: 0644]

index 6423947..db7078a 100644 (file)
@@ -2,7 +2,7 @@
 <html lang="en">
 <head>
 <title>Sixth 3D engine demos</title>
 <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">
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <meta name="generator" content="Org-mode">
@@ -226,35 +226,296 @@ published by the Free Software Foundation.
 
 
 <div id="outline-container-sec-1" class="outline-2">
 
 
 <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>
 <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>
 
+<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>
 
 <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>
 </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>
 </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">&lt;space&gt;</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">
 </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>
 </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>
 <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>
index 1333873..1375cac 100644 (file)
 #+HTML_HEAD:   pre {background-color: #111; color: #ccc;}
 #+HTML_HEAD: </style>
 
 #+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.
diff --git a/doc/screenshots/.thumbnails/another test scene (5362752B).jpeg b/doc/screenshots/.thumbnails/another test scene (5362752B).jpeg
deleted file mode 100644 (file)
index 68e88df..0000000
Binary files a/doc/screenshots/.thumbnails/another test scene (5362752B).jpeg and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/another test scene (62C8D31D).jpeg b/doc/screenshots/.thumbnails/another test scene (62C8D31D).jpeg
deleted file mode 100644 (file)
index 37b2943..0000000
Binary files a/doc/screenshots/.thumbnails/another test scene (62C8D31D).jpeg and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/mathematical formulas (7454DC19).jpeg b/doc/screenshots/.thumbnails/mathematical formulas (7454DC19).jpeg
deleted file mode 100644 (file)
index edd43e5..0000000
Binary files a/doc/screenshots/.thumbnails/mathematical formulas (7454DC19).jpeg and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/mathematical formulas (82926553).jpeg b/doc/screenshots/.thumbnails/mathematical formulas (82926553).jpeg
deleted file mode 100644 (file)
index 83db0ac..0000000
Binary files a/doc/screenshots/.thumbnails/mathematical formulas (82926553).jpeg and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/metadata_6.dat b/doc/screenshots/.thumbnails/metadata_6.dat
deleted file mode 100644 (file)
index d041cab..0000000
Binary files a/doc/screenshots/.thumbnails/metadata_6.dat and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (1F22E82D).jpeg b/doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (1F22E82D).jpeg
deleted file mode 100644 (file)
index 774f66a..0000000
Binary files a/doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (1F22E82D).jpeg and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (534B3488).jpeg b/doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (534B3488).jpeg
deleted file mode 100644 (file)
index f385768..0000000
Binary files a/doc/screenshots/.thumbnails/raytracing fractal in voxel polygon hybrid scene (534B3488).jpeg and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/text editors (C0263A2).jpeg b/doc/screenshots/.thumbnails/text editors (C0263A2).jpeg
deleted file mode 100644 (file)
index f8543d5..0000000
Binary files a/doc/screenshots/.thumbnails/text editors (C0263A2).jpeg and /dev/null differ
diff --git a/doc/screenshots/.thumbnails/text editors (CBB27271).jpeg b/doc/screenshots/.thumbnails/text editors (CBB27271).jpeg
deleted file mode 100644 (file)
index 59b35ea..0000000
Binary files a/doc/screenshots/.thumbnails/text editors (CBB27271).jpeg and /dev/null differ
diff --git a/doc/screenshots/another test scene.png b/doc/screenshots/another test scene.png
deleted file mode 100644 (file)
index 9ddf563..0000000
Binary files a/doc/screenshots/another test scene.png and /dev/null differ
diff --git a/doc/screenshots/index.html b/doc/screenshots/index.html
deleted file mode 100644 (file)
index c07b289..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<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>
diff --git a/doc/screenshots/life.png b/doc/screenshots/life.png
new file mode 100644 (file)
index 0000000..dbdc2dd
Binary files /dev/null and b/doc/screenshots/life.png differ
diff --git a/doc/screenshots/sinus heightmaps and sphere.png b/doc/screenshots/sinus heightmaps and sphere.png
new file mode 100644 (file)
index 0000000..9ddf563
Binary files /dev/null and b/doc/screenshots/sinus heightmaps and sphere.png differ
diff --git a/pom.xml b/pom.xml
index 808d8d3..d58b8b2 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -28,7 +28,7 @@
         <dependency>
             <groupId>eu.svjatoslav</groupId>
             <artifactId>sixth-3d</artifactId>
         <dependency>
             <groupId>eu.svjatoslav</groupId>
             <artifactId>sixth-3d</artifactId>
-            <version>1.0</version>
+            <version>1.1</version>
         </dependency>
 
         <dependency>
         </dependency>
 
         <dependency>
index a81cbb2..e629421 100644 (file)
@@ -11,7 +11,7 @@
     <orderEntry type="inheritedJdk" />
     <orderEntry type="sourceFolder" forTests="false" />
     <orderEntry type="library" scope="TEST" name="Maven: junit:junit:4.8.1" level="project" />
     <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>
     <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>
index e77b53f..1f868b9 100644 (file)
@@ -21,33 +21,15 @@ class MenuPanel extends JPanel {
 
     public MenuPanel() {
 
 
     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
         final GroupLayout groupLayout = new GroupLayout(this);
         groupLayout
                 .setHorizontalGroup(groupLayout
@@ -65,7 +47,7 @@ class MenuPanel extends JPanel {
                                                                 groupLayout
                                                                         .createSequentialGroup()
                                                                         .addComponent(
                                                                 groupLayout
                                                                         .createSequentialGroup()
                                                                         .addComponent(
-                                                                                lblNewLabel,
+                                                                                chooseExample,
                                                                                 GroupLayout.PREFERRED_SIZE,
                                                                                 426,
                                                                                 GroupLayout.PREFERRED_SIZE)
                                                                                 GroupLayout.PREFERRED_SIZE,
                                                                                 426,
                                                                                 GroupLayout.PREFERRED_SIZE)
@@ -81,37 +63,37 @@ class MenuPanel extends JPanel {
                                                                                         .createParallelGroup(
                                                                                                 Alignment.TRAILING)
                                                                                         .addComponent(
                                                                                         .createParallelGroup(
                                                                                                 Alignment.TRAILING)
                                                                                         .addComponent(
-                                                                                                btnNewButton_4,
+                                                                                                showOctree,
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
-                                                                                                btnNewButton_3,
+                                                                                                showMathGraphs,
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
-                                                                                                btnNewButton_2,
+                                                                                                showPointCloud,
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
-                                                                                                button,
+                                                                                                showRain,
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
                                                                                                 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(
                                                                                                 Alignment.LEADING,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 Short.MAX_VALUE)
                                                                                         .addComponent(
-                                                                                                btnNewButton,
+                                                                                                showTextEditors,
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE))
                                                                                                 GroupLayout.DEFAULT_SIZE,
                                                                                                 331,
                                                                                                 Short.MAX_VALUE))
@@ -121,31 +103,30 @@ class MenuPanel extends JPanel {
                 groupLayout
                         .createSequentialGroup()
                         .addGap(7)
                 groupLayout
                         .createSequentialGroup()
                         .addGap(7)
-                        .addComponent(lblNewLabel, GroupLayout.PREFERRED_SIZE,
+                        .addComponent(chooseExample, GroupLayout.PREFERRED_SIZE,
                                 58, GroupLayout.PREFERRED_SIZE)
                         .addPreferredGap(ComponentPlacement.RELATED)
                                 58, GroupLayout.PREFERRED_SIZE)
                         .addPreferredGap(ComponentPlacement.RELATED)
-                        .addComponent(btnNewButton)
+                        .addComponent(showTextEditors)
                         .addPreferredGap(ComponentPlacement.RELATED)
                         .addPreferredGap(ComponentPlacement.RELATED)
-                        .addComponent(btnNewButton_1)
+                        .addComponent(showSinusMap)
                         .addPreferredGap(ComponentPlacement.RELATED)
                         .addPreferredGap(ComponentPlacement.RELATED)
-                        .addComponent(button)
+                        .addComponent(showRain)
                         .addPreferredGap(ComponentPlacement.RELATED)
                         .addPreferredGap(ComponentPlacement.RELATED)
-                        .addComponent(btnNewButton_2)
+                        .addComponent(showPointCloud)
                         .addPreferredGap(ComponentPlacement.RELATED)
                         .addPreferredGap(ComponentPlacement.RELATED)
-                        .addComponent(btnNewButton_3)
+                        .addComponent(showMathGraphs)
                         .addPreferredGap(ComponentPlacement.RELATED)
                         .addPreferredGap(ComponentPlacement.RELATED)
-                        .addComponent(btnNewButton_4)
+                        .addComponent(showOctree)
                         .addContainerGap(137, Short.MAX_VALUE)));
         setLayout(groupLayout);
 
     }
 
                         .addContainerGap(137, Short.MAX_VALUE)));
         setLayout(groupLayout);
 
     }
 
-    private class SwingAction extends AbstractAction {
+    private class ShowTextEditors extends AbstractAction {
         private static final long serialVersionUID = 5197962166765841015L;
 
         private static final long serialVersionUID = 5197962166765841015L;
 
-        public SwingAction() {
+        public ShowTextEditors() {
             putValue(NAME, "Text editors");
             putValue(NAME, "Text editors");
-            putValue(SHORT_DESCRIPTION, "Some short description");
         }
 
         @Override
         }
 
         @Override
@@ -154,27 +135,24 @@ class MenuPanel extends JPanel {
         }
     }
 
         }
     }
 
-    private class SwingAction_1 extends AbstractAction {
+    private class ShowSinusMap extends AbstractAction {
         private static final long serialVersionUID = -896479509963403828L;
 
         private static final long serialVersionUID = -896479509963403828L;
 
-        public SwingAction_1() {
+        public ShowSinusMap() {
             putValue(NAME, "Wireframe sphere and ploygon landscape");
             putValue(NAME, "Wireframe sphere and ploygon landscape");
-            putValue(SHORT_DESCRIPTION, "Some short description");
         }
 
         @Override
         public void actionPerformed(final ActionEvent e) {
             SphereDemo.main(null);
         }
 
         @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;
 
         private static final long serialVersionUID = 8566009849873897321L;
 
-        public SwingAction_2() {
+        public ShowRain() {
             putValue(NAME, "Raining numbers");
             putValue(NAME, "Raining numbers");
-            putValue(SHORT_DESCRIPTION, "Some short description");
         }
 
         @Override
         }
 
         @Override
@@ -187,12 +165,11 @@ class MenuPanel extends JPanel {
         }
     }
 
         }
     }
 
-    private class SwingAction_3 extends AbstractAction {
+    private class ShowPointcloud extends AbstractAction {
         private static final long serialVersionUID = -5369105936409884389L;
 
         private static final long serialVersionUID = -5369105936409884389L;
 
-        public SwingAction_3() {
+        public ShowPointcloud() {
             putValue(NAME, "Pointcloud galaxy");
             putValue(NAME, "Pointcloud galaxy");
-            putValue(SHORT_DESCRIPTION, "Some short description");
         }
 
         @Override
         }
 
         @Override
@@ -201,12 +178,11 @@ class MenuPanel extends JPanel {
         }
     }
 
         }
     }
 
-    private class SwingAction_4 extends AbstractAction {
+    private class ShowMathGraphs extends AbstractAction {
         private static final long serialVersionUID = -8486796142555764460L;
 
         private static final long serialVersionUID = -8486796142555764460L;
 
-        public SwingAction_4() {
+        public ShowMathGraphs() {
             putValue(NAME, "Mathematical graphs");
             putValue(NAME, "Mathematical graphs");
-            putValue(SHORT_DESCRIPTION, "Some short description");
         }
 
         @Override
         }
 
         @Override
@@ -219,12 +195,11 @@ class MenuPanel extends JPanel {
         }
     }
 
         }
     }
 
-    private class SwingAction_5 extends AbstractAction {
+    private class ShowOctree extends AbstractAction {
         private static final long serialVersionUID = -6210703594848004946L;
 
         private static final long serialVersionUID = -6210703594848004946L;
 
-        public SwingAction_5() {
+        public ShowOctree() {
             putValue(NAME, "Volumetric Octree");
             putValue(NAME, "Volumetric Octree");
-            putValue(SHORT_DESCRIPTION, "Some short description");
         }
 
         @Override
         }
 
         @Override
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
new file mode 100755 (executable)
index 0000000..4d1cca0
--- /dev/null
@@ -0,0 +1,128 @@
+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());
+    }
+
+}
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
new file mode 100644 (file)
index 0000000..527a6a2
--- /dev/null
@@ -0,0 +1,107 @@
+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);
+    }
+
+}
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
new file mode 100644 (file)
index 0000000..ee7b0aa
--- /dev/null
@@ -0,0 +1,156 @@
+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
new file mode 100644 (file)
index 0000000..81e7198
--- /dev/null
@@ -0,0 +1,41 @@
+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
+        );
+    }
+
+}