Initial commit
commit
0e27f4cc94
|
@ -0,0 +1,3 @@
|
|||
www.emamaker.com
|
||||
emamaker.com
|
||||
emamaker.codeberg.page
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>Atom feed</title>
|
||||
<subtitle></subtitle>
|
||||
<link href="https://emamaker.com/atom.xml/" rel="self" />
|
||||
<link href="https://emamaker.com/" />
|
||||
<id>https://emamaker.com</id>
|
||||
<updated>2023-01-19T12:45:17+01:00</updated>
|
||||
<entry>
|
||||
<title>Developing a Voxel Engine</title>
|
||||
<link href="/projects/voxelengine.html" />
|
||||
<id>/projects/voxelengine.html</id>
|
||||
<updated>2023-01-06 23:07:22.301262025 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>Google Meet Bot attends online lessons for me</title>
|
||||
<link href="/projects/googlemeetbot.html" />
|
||||
<id>/projects/googlemeetbot.html</id>
|
||||
<updated>2023-01-06 21:56:22.760129090 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>MakerFaire Rome 2017</title>
|
||||
<link href="/events/makerfaire2017.html" />
|
||||
<id>/events/makerfaire2017.html</id>
|
||||
<updated>2023-01-05 23:12:11.151727127 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>EmaMaker&#8217;s blog | Events</title>
|
||||
<link href="/events/index.html" />
|
||||
<id>/events/index.html</id>
|
||||
<updated>2023-01-05 22:13:20.140865078 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>EmaMaker&#8217;s Blog | Projects</title>
|
||||
<link href="/projects/index.html" />
|
||||
<id>/projects/index.html</id>
|
||||
<updated>2023-01-05 22:12:57.653996091 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>Voxel notes</title>
|
||||
<link href="/notes/voxel.html" />
|
||||
<id>/notes/voxel.html</id>
|
||||
<updated>2023-01-04 03:07:46.913167282 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>EmaMaker&#8217;s Blog</title>
|
||||
<link href="/index.html" />
|
||||
<id>/index.html</id>
|
||||
<updated>2023-01-02 12:14:37.793859526 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>SPQR Robotics Team</title>
|
||||
<link href="/projects/spqr.html" />
|
||||
<id>/projects/spqr.html</id>
|
||||
<updated>2023-01-02 12:09:01.573397744 +0100</updated>
|
||||
</entry>
|
||||
<entry>
|
||||
<title>EmaMaker&#8217;s blog | Notes</title>
|
||||
<link href="/notes/index.html" />
|
||||
<id>/notes/index.html</id>
|
||||
<updated>2023-01-01 19:34:48.045143605 +0100</updated>
|
||||
</entry>
|
||||
</feed>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>EmaMaker&#8217;s blog | Events</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<p>Report of events I take part in, or simply go to.</p>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,69 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>MakerFaire Rome 2017</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<h1 id="makerfaire-rome-2017">MakerFaire Rome 2017</h1>
|
||||
|
||||
<h2 id="makerfaire-2017-and-our-project">MakerFaire 2017 and our project</h2>
|
||||
|
||||
<p>The December of 2017 started with a beautiful experience: I took part, with some other friends and our parents, to the MakerFaire 2017. We had our own stand and we showed to the big public of the Faire our project. What was is about? It’s called 3DPacRobotMan and it’s a real-life version of the Pac-Man game. Pac-Man is a videogame that came out in the ‘80s and still today is very famous.</p>
|
||||
|
||||
<p><img src="//emamaker.com/resources/events/makerfaire2017/makerfaire1.jpg" />
|
||||
Our version uses new technologies to make a funnier and cooperative version of the game:</p>
|
||||
|
||||
<p>The field is all made of laser-cut wood. On the underside, the field is divided into sections. Every section has a board that controls a group of reed sensors. This board communicates in SPI with a central shield, which takes count of the reed sensors activated under all the field, turning off the corresponding LEDs, mimicking the coins in the original game.
|
||||
As in the original game, there are five characters: one is the Pac-Man and the others are the ghosts. The ghosts have to catch the Pac-Man, which has to escape from them. If the ghosts catch the Pac-Man they win, otherwise is the Pac-Man to win. Again, a reed sensor on the PacMan recognizes when the ghosts touch it. The robots are made using Arduino Uno modified Boards and remote controlled with Radio Frequences @2.4GHz.</p>
|
||||
|
||||
<p>I took care of the scenic (so to speak) part: a Raspberry Pi serial communicates with the field to let the players see the score, the highscore, and plays the game sounds.</p>
|
||||
|
||||
<p><img src="//emamaker.com/resources/events/makerfaire2017/makerfaire2.jpg" /></p>
|
||||
|
||||
<p><em>Note as of 05 Jan 2023, as I’m porting this to the new website: Everything was made in Java Swing. This was the only language I knew at the time, and I admit it was pretty bad. Swing GUIs do not update if no callbacks are called, activated by user action. My workaround was to create a button with transparent background and no text on it, and I had a script moving the mouse and simulating left clicks (I do not remember if it was external, launching a script from the terminal or integrated in my Java program).
|
||||
If I was to do it again today, I would make it in Processing: easy serial communication with arduino, no reason to do weird workarounds to update the gui, easy sound playing</em>
|
||||
<em>Cherry on top, I actually lost the source code to this master piece of a program.</em></p>
|
||||
|
||||
<p><img src="//emamaker.com/resources/events/makerfaire2017/makerfaire3.jpg" /></p>
|
||||
|
||||
<h2 id="3d-pac-robot-man-on-the-magpi">3d Pac Robot Man on ‘The MagPi’</h2>
|
||||
|
||||
<p>Do you know the Raspberry Pi? It’s a credit-card sized computer, that you can buy for just 35$.
|
||||
The Raspberry Pi Foundation has its official magazine, called “The MagPi”. I had the luck (and the guts to ask them) to speak with the Raspberry Pi Foundation guys at the MakerFaire 2017 and I told them about our project.
|
||||
They liked it and they published and article about our project in the February 2018 Issue of the MagPi. Down here there are the photos of the two pages about our project, but you can always download it for free from <a href="https://emamaker.com/magpi.raspberrypi.com/issues/66">The MagPi’s official website</a>. I also have a <a href="https://emamaker.com/emamaker.com/resources/events/makerfaire2017/TheMagPi66.pdf">mirror on this website</a>, should the link be dead.
|
||||
<img src="//emamaker.com/resources/events/makerfaire2017/makerfaire4.jpg" />
|
||||
<img src="//emamaker.com/resources/events/makerfaire2017/makerfaire5.jpg" /></p>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,62 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>EmaMaker&#8217;s Blog</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<p>Hello, I’m Emanuele, and this is my website!</p>
|
||||
|
||||
<p>I like coding, electronics and robotics :)</p>
|
||||
|
||||
<p>I started messing around with LEGO Mindstorm when I was around 10, then I started using Arduino while in middle school.
|
||||
While in high school, I studied industrial automation <a href="./projects/spqr.html">and had a chance to pursue my passion for robotics</a>. I’m currently studying to get a bachelor degree in automation engineering.
|
||||
In this little corner of the web I will write about my projects, ideas and notes on the stuff I think could be useful to others, or that I just feel like sharing.</p>
|
||||
|
||||
<p>I have never really fancied the use of social networks, I only ever had an <a href="https://instagram.com/emamaker">Instagram account</a> which is now quite abandoned. I currently only browse Reddit and YouTube to keep up with the stuff I like, via FOSS apps like Infinity and NewPipe.</p>
|
||||
|
||||
<p>I really like the style of HTML-and-CSS static websites, hence the simple style of this one. This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>, a static website generator written in POSIX compliant sh <a href="https://alemauri.eu"> by my dear friend Alessandro Mauri. Check him out!</a></p>
|
||||
|
||||
<p>Enjoy!</p>
|
||||
|
||||
<div id="map">
|
||||
<h2 id="Pages">Latest Posts</h2>
|
||||
<p><a href="/projects/voxelengine.html">2023-01-06 - Developing a Voxel Engine</a></p>
|
||||
<p><a href="/projects/googlemeetbot.html">2023-01-06 - Google Meet Bot attends online lessons for me</a></p>
|
||||
<p><a href="/events/makerfaire2017.html">2023-01-05 - MakerFaire Rome 2017</a></p>
|
||||
<p><a href="/notes/voxel.html">2023-01-04 - Voxel notes</a></p>
|
||||
<p><a href="/projects/spqr.html">2023-01-02 - SPQR Robotics Team</a></p>
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>EmaMaker&#8217;s blog | Notes</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<p>Here you can find a list of notes I take about the ideas I come up with. I take notes directly in markdown, which makes them easy t oconvert into html to be presented here.</p>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,167 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Voxel notes</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<h1 id="old-voxel-engine">Old voxel engine:</h1>
|
||||
|
||||
<h2 id="data-structure">Data structure</h2>
|
||||
|
||||
<p>Used 1d arrays for storing blocks in Chunks. This is good enough, 1d arrays are faster to poll than 3d arrays. Memory usage shouldn’t be that bad.</p>
|
||||
|
||||
<p>Used 3d arrays for storing chunks in the world, this is VERY VERY bad, there’s a lot of wasted memory. Each update loop the engine looked in a sphere around the player of radius RENDER DISTANCE and updated each chunk that needed it. Then each chunk, using a JME3 Abstract Control was updated each loop and the chunk was removed or added to the scene if needed. This infact created a constant usage of memory, but a limited world. </p>
|
||||
|
||||
<h2 id="save-files">Save files</h2>
|
||||
|
||||
<p>Saved and loaded from file by saving every single block, again very very bad. Could create up to GIGABYTES in save files</p>
|
||||
|
||||
<h1 id="new-voxel-engine">New voxel engine</h1>
|
||||
|
||||
<h2 id="data-structure-1">Data Structure</h2>
|
||||
|
||||
<p>Using interval trees to store blocks in Chunks, as suggested by <a href="https://0fps.net/2012/01/14/an-analysis-of-minecraft-like-engines/">0fps</a> and on <a href="https://teddit.pussthecat.org/r/VoxelGameDev/comments/elap1u/using_interval_maps_instead_of_arrays_for_storing/">reddit</a>. Thought about using SVOs (Sparse Voxel Octrees) as described in the nvidia paper or even SVDAG (Sparse Voxel Direct Acyclic Graph) but they just don’t look like the right tool for job.</p>
|
||||
|
||||
<p>Chunks are then stored into an hashmap as they get created and destroyed. This ensured O(1) access to a Chunk and good memory usage, while not giving limits to the size of the world
|
||||
Interval trees kinda give built-in memory compression like in Run length encoding, with O(log n) average and O(n) worst case time to add or remove nodes. I’m not really removing nodes right now when needed, and they tend to grow pretty large in memory footprint as of (15/08/2002).</p>
|
||||
|
||||
<p>Actually Interval Trees don’t really seem like the best tool for the job either, as they require a start and an end to an interval, while I just really need to know the start of the interval (like in Run Length encoding) representing a run of identical blocks, and assume that it will either continue until the end of there will be a new node in the tree representing the start of the new interval right after it. I will probably be better off using some kind of Binary Research Tree, storing a key-value pair where the key is the start of the run (interval) and the value is the type of block. Probably the best option is to use a Red-Black Tree instead of a plain Binary Research Tree. This is similar to what the <a href="!missing_link">reddit guy</a> did, except he was using C++ IntervalMaps, which are implemented as Red-Black Trees </p>
|
||||
|
||||
<h3 id="update">Update</h3>
|
||||
|
||||
<p>I implemented IntervalMaps starting from Java’s java.util.TreeMaps, which are implemented as Red-Black Trees, and had a huge reduction in memory usage
|
||||
improvement (down to 80-85 MB of memory from 400+).
|
||||
For further compression, i think some kind of space-filling curve could compress the tree even further by better expressing local conglomerates of the same kind of blocks in the 3d-to-1d flatteing. By researching space-filling curves, on <a href="!https://en.wikipedia.org/wiki/Space-filling_curve">wikipedia</a>, I’m lead to think that an Hilbert Curve is better than <a href="!https://en.wikipedia.org/wiki/Z-order_curve">Morton</a> curves or Morton ordering for my scope, <a href="!http://www.volumesoffun.com/implementing-morton-ordering-for-chunked-voxel-data/index.html">although I’ve seen morton ordering used in big voxel engines projects</a>. I will try both and check which one compresses better.
|
||||
By researching 3D Hilbert curves, i stumbled upon <a href="https://eisenwave.github.io/voxel-compression-docs/rle/hilbert_curves.html">this website</a>, which brings to <a href="!http://and-what-happened.blogspot.com/2011/08/fast-2d-and-3d-hilbert-curves-and.html">this other site for C implementations</a></p>
|
||||
|
||||
<h3 id="update-2">Update 2</h3>
|
||||
|
||||
<p>Implemented Hilbert Curves and re-run benchmarks on all branches and techniques used until now. I apparently had huge problems in my old benchmarks, because I reported very different numbers across all tests, even on stuff I haven’t touched in a while.</p>
|
||||
|
||||
<p>I tested these three techniques:
|
||||
- Interval Trees, with my own (crappy in some ways) implementation, with nested iteration as a 3d-to-1d flattening
|
||||
- Interval Maps, with nested iteration as a 3d-to-1d flattening
|
||||
- Interval Maps, with hilbert curves</p>
|
||||
|
||||
<p>They all use chunk states instead of queues, as continously filling and empting queues was not making the garbage collector happy and some huge memory usage spikes could be seen in VisualVM</p>
|
||||
|
||||
<p>In the end, all the techniques seem to perform about equal in my base benchmark (creating a cube of render_distance*2 side, generated with arrayGenerateCorner. Cubical chunks with a side of 16 voxels), reporting:</p>
|
||||
|
||||
<p>RENDER_DISTANCE = 8</p>
|
||||
|
||||
<ul>
|
||||
<li><p>Chunk size 32 (just creating chunks, no world update)</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Normal Heap (used/allocated)</th>
|
||||
<th>After 1GC (used/allocated)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Interval Trees (nested iteration)</td>
|
||||
<td>74/154</td>
|
||||
<td>32/112</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Interval Maps (space filling)</td>
|
||||
<td>128/210</td>
|
||||
<td>26/98</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></li>
|
||||
<li><p>Chunk size 16 (normal world update loop)</p>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Normal Heap (used/allocated)</th>
|
||||
<th>After 1GC (used/allocated)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Interval Trees (nested iteration)</td>
|
||||
<td>148/196</td>
|
||||
<td>81/196</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Interval Maps (space filling - Hilbert Bits 2)</td>
|
||||
<td>100/193</td>
|
||||
<td>59/193</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Interval Maps (space filling - Hilbert Bits 4)</td>
|
||||
<td>88/192</td>
|
||||
<td>55/193</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></li>
|
||||
</ul>
|
||||
|
||||
<p>To be noted:
|
||||
- IntervalTrees seem to have a less “spikey” use of ram, but that could be due to other causes rather than the data structure itself
|
||||
- Using a spacefilling curve requires more calculations than nested iteration, but that can be optimized
|
||||
- The manual GC call just cuts the allocated heap, as the used heap already falls on its own once chunk generation has finished</p>
|
||||
|
||||
<p>I honestly cannot explain myself how intervaltrees can have such a similar memory usage to intervalmaps. On one hand, I know that my implementation of intervaltrees lacks the removal of adjacent similar nodes, and that leaves a lot of unneeded nodes around. Maybe this could be better noted once block picking is added. As of right now, this situation doesn’t really occur.
|
||||
On the other hand, java’s implementation of TreeMaps has some stuff that I don’t really need, and the memory size of the structure itself could be reduced if I were to reimplement it to better suit my needs.</p>
|
||||
|
||||
<p>Also I haven’t tested interval trees with a space filling curve, but I don’t think that would change much.</p>
|
||||
|
||||
<h2 id="ideas">Ideas</h2>
|
||||
|
||||
<ul>
|
||||
<li><p>I’m currently using greedy meshing to obtain a triangle mesh out of the interval tree, by first converting it into an array. It is possible that, by changing the function i use to flatten a 3d index into a 2d one, the interval tree could be used directly into the greedy meshing function without a preliminary conversion to an array. The use of an array could still be need for fast chunk generation though</p></li>
|
||||
<li><p>If going with bigger chunks, probably it will be best to just transform the tree into an array past a certain height (meaning very different blocks)</p></li>
|
||||
<li><p>At some point, chunks need to be unloaded from memory. This can be done in three stages:</p>
|
||||
|
||||
<ol>
|
||||
<li>Chunks within render distance are shown and eventual logic gets updated</li>
|
||||
<li>Chunks little outside of render distance are show but no logic gets update (what about LODs?)</li>
|
||||
<li>Chunks that havebeen far from render distance for a short time are kept in a separate hashmap with just the deltas stored. After enough time has passed, they get dumped to the HDD and completely unloaded from memory</li>
|
||||
</ol>
|
||||
|
||||
<p>This method makes an assumption on chunk structure, such that generation is done at runtime and only modifications are permanently stored. This also means that generation data and modification data are stored in two different places, possibly using two different trees, a tree and an array, or something else</p></li>
|
||||
<li><p>SVDAGs look like an interesting structure to look more deeply into and try to implement in some way. Maybe textures will be difficult to implement, but they would probably give access to some non-cubical blocks, by making them up of blocks smaller that the 1-Unit size decided for a single voxel</p></li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,87 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Google Meet Bot attends online lessons for me</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<h2 id="before-reading">Before Reading</h2>
|
||||
|
||||
<p>As always, the source code for this Google Meet Bot is available on my <a href="https://github.com/EmaMaker/GoogleMeetBot">github</a> profile. You can even download it and set it up for your own use following the instructions! If you want to see the bot in action take a look here</p>
|
||||
|
||||
<h1 id="video-demo-youtubeinvidious">Video Demo <a href="https://www.youtube.com/watch?v=ZaBPLZkqqas">(YouTube)</a><a href="https://invidious.snopyta.org/watch?v=ZaBPLZkqqas">(Invidious)</a></h1>
|
||||
|
||||
<h2 id="the-problem">The Problem</h2>
|
||||
|
||||
<p>I’ll be honest, I’ve never been the kind of person that wakes up early in the morning and it’s super energetic right off the bat. Even if i wake up at 7am, getting out of the bed takes me ages. Now, since the COVID-19 outbreak in my country, schools have moved to online lessons countrywide. Even if by now we go physically to school for 75% of the week, we still have to attend online classes for the other 25%. This whole time, knowing I had to stay at home to follow my lessons made waking up early even harder for me. And apparently keeping note of who arrives to a lesson late is apparently a huge problem, which neither me nor my teachers want to deal with. </p>
|
||||
|
||||
<h2 id="what-do-do">What do do?</h2>
|
||||
|
||||
<p>I had to do something for this situation, and getting up in time was simply not an option. I needed something that could join lessons on time for me, which allowed me to sleep more. So i needed something to automate my computer, but how? I could write some program that simulated the mouse moving and clicking, but I had to do it in the past and I knew it was terrible idea, so I ditched it. Yet, i needed something to simulate a person using the browser.</p>
|
||||
|
||||
<h2 id="looking-at-old-projects">Looking at old projects</h2>
|
||||
|
||||
<p>as I said, using some kind of program to virtually move the mouse and click stuff was totally not a good idea. At least not writing my own. Then i remembered that some time ago I worked on an <a href="https://github.com/EmaMaker/AccountChecker">Account Checker script</a> for a friend. It was basically a program which, given a list of usernames and passwords, would try to login into websites. This was a nice and quick project that you can find here. I might do a post on it some day.</p>
|
||||
|
||||
<p>The Account Checker was based on the <a href="https://github.com/nsgodshall/Hatch">nsgodshall’s fork</a> of <a href="https://github.com/zshell/Hatch">zshell’s Hatch</a>, it was written in Python and used a module called <a href="https://www.selenium.dev/">Selenium</a>, which was exactly what i needed.</p>
|
||||
|
||||
<h2 id="selenium">Selenium</h2>
|
||||
|
||||
<p>It’s a simple yet extremely powerful website automation tool. Selenium can open an automated Firefox window, and it can simulate the click of buttons or typing of keys like if a person was using it.
|
||||
To do this, the browser has to be ready for automation. For Chrome, this means installing the chromedriver and giving the right path to it to the script. For Firefox, it means doing the same thing with the geckodriver.
|
||||
I decided to settle with Firefox because Chrome was giving me some strange problems with login in the early tests. While I was thinking of this, and had already made a somewhat working example, a classmate of mine, to which I had spoken about this project before, sent me <a href="https://www.youtube.com/watch?v=7neSueHsyY0">this video by TechRaj</a>. TechRaj made a bot to automatically join Microsoft Teams meetings, the same concept could be applied to Google Meet, but it had some serious problems to be solved.</p>
|
||||
|
||||
<h2 id="the-bot">The Bot</h2>
|
||||
|
||||
<p>The most important problem in this case, is that Google, unlike Microsoft, doesn’t allow google accounts to be joined from automated browser sessions. Second problem, is that, unlike TechRaj does, CSS Selectors cannot be used to select the components, since the selector of a component changes on a per-meeting basis on GMeets. This second problem is quite easy to resolve by using XPATHs instead of CSS Selectors. An XPATH just a string that describes the position of a component in an HTML structure. XPATH are static, unless someone changes the HTML structure of the page, which shouldn’t happen really often on a service like GMeet.</p>
|
||||
|
||||
<p>The account problem is a little trickier to workaround, but I managed to find a way. FireFox has profiles, which retains information about the browsing history, cookies and, most importantly, accounts that are logged in. So we could create a new FireFox profile, manually login into the needed Google Account via GMail and let the profile store the account. Since this step has been done manually, without an automated browser, Google will let it login into the google account with no problems.</p>
|
||||
|
||||
<p>Then, using Selenium, we can open a new FireFox window that uses the profile we just created, and it will be automatically logged in into Google, struggle free.</p>
|
||||
|
||||
<p>from this point on is just a matter of using <strong>WebDriver.get</strong>, <strong>WebDriver.click</strong> and <strong>WebDriver.send_keys</strong> to click redirect the browser to the given Meet link, click the buttons to mute camera and microphone, join the call and eventually type something in the chat. At this point there’s only a scheduling system missing.Scheduling</p>
|
||||
|
||||
<p>It wouldn’t be a real bot if it wasn’t able to automatically join classes at the right time, every day. Searching around i found the <strong>schedule</strong> module for python. Basically, as long as script runs, it will execute the given action at the right time of the right day. I did another bit of manual work and programmed the bot with my current lessons schedule.</p>
|
||||
|
||||
<p>Of course, a teacher could be late, so the bot is programmed to retry joining a meeting every minute if a failure of any type should occur.</p>
|
||||
|
||||
<p>Running in the background is the only thing left: my computer runs ArchLinux with KDE Plasma as Desktop Environment. KDE Plasma allows the user to create multiple Activities, which are basically virtual desktop isolated from each other. I created an activity for my school stuff, and let the bot run there.</p>
|
||||
|
||||
<h2 id="conclusion-and-final-considerations">Conclusion and Final Considerations</h2>
|
||||
|
||||
<p>The bot is lightweight and easy to set up and use. I’ve been running this Google Meet bot for the past couples of months and hasn’t failed on me since, and I still haven’t got busted by my teachers.</p>
|
||||
|
||||
<h1 id="video-demo-youtubeinvidious-1">Video Demo <a href="https://www.youtube.com/watch?v=ZaBPLZkqqas">(YouTube)</a><a href="https://invidious.snopyta.org/watch?v=ZaBPLZkqqas">(Invidious)</a></h1>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>EmaMaker&#8217;s Blog | Projects</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<p>TODO</p>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>SPQR Robotics Team</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<p>TODO</p>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,130 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="stylesheet" href="//emamaker.com/styles.css">
|
||||
<link rel="icon" type="image/png" href="//emamaker.com/favicon.png">
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<title>Developing a Voxel Engine</title>
|
||||
</head>
|
||||
<body>
|
||||
<header><center>
|
||||
<a href="//emamaker.com/index.html">Home</a>
|
||||
|
|
||||
<a href="//emamaker.com/projects/index.html">Projects</a>
|
||||
|
|
||||
<a href="//emamaker.com/notes/index.html">Notes</a>
|
||||
|
|
||||
<a href="https://git.emamaker.com/EmaMaker">Gitea</a>
|
||||
|
|
||||
<a href="https://github.com/EmaMaker">Github</a>
|
||||
|
|
||||
<a href="https://instagram.com/EmaMaker">Instagram</a>
|
||||
</center>
|
||||
</header>
|
||||
<article>
|
||||
|
||||
<h1 id="developing-a-voxel-engine">Developing a Voxel Engine</h1>
|
||||
|
||||
<p>Almost two years ago I decided to start working on a Voxel Engine –
|
||||
knowing almost nothing about voxel engines.
|
||||
This is not a guide to voxel engines nor a tutorial about making one,
|
||||
it’s just the report of my experience from scratch to a fully working
|
||||
project.</p>
|
||||
|
||||
<p>I decided to go with
|
||||
<a href="http://jmonkeyengine.org">jMonkeyEngine</a>, as Java was the only language I knew two years ago and I didn’t want to start from raw <a href="http://lwjgl.org">LWJGL</a>, and this engine was easy enough to use for me.
|
||||
Nothing excludes that the code can’t be ported to other languages, and it’s probably something I’ll do to learn new languages quickly. Maybe in the future I can port this engine to other languages or rewrite it using OpenGL with <a href="http://lwjgl.org">LWJGL</a>.</p>
|
||||
|
||||
<h2 id="image-here">Image here</h2>
|
||||
|
||||
<p>
|
||||
All my code is available on my <a href="https://github.com/EmaMaker">GitHub profile:
|
||||
https://github.com/EmaMaker</a>
|
||||
</p>
|
||||
|
||||
<p><strong>Face Culling</strong>
|
||||
My first test worked using strange formula to have less cubes as position on the y axis increased and used full cubes with a yellow-purple texture to test the borders. This is the first big error when making a voxel engine.
|
||||
Even if you see a world made out of cubes, in reality there are any. All the “cubes” are made of simple quads that appear or disappear based on what you need. For example, if you have two adjacent cubes with each cube touching a single face of the other, both cubes will have a face that won’t be seen by the user, so the simplest thing to do is just not rendering them and save workload on the GPU. This method is called Face Culling.
|
||||
You can read more about rendering methods for voxel engines <a href="https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/">in this very interesting article by 0fps</a>.
|
||||
I spent some months working on a better version of this face culling algorithm, fixing and tweaking the RAM usage due to some bad-practices I’ve used during the first test. This version was based on a <em>Cell</em> object, that kept note of the faces to show during rendering. <em>Cells</em> are grouped into <em>Chunks</em>, making the progressive world generation much easier.</p>
|
||||
|
||||
<p><em>Chunks</em> store a three-dimensional array of <em>Cells</em>, while the entire World is stored in a three-dimensional array of <em>Chunks</em>. I kept this structure for all the development.</p>
|
||||
|
||||
<p>But there were still some problems with this: the <em>Cell</em> generated six different objects that had do be rendered separately on screen: it used too much RAM and was still too much for the GPU. Despite this, it run at
|
||||
100fps on my Dell XPS M1330, which now is a 12-years-old laptop.
|
||||
But when it came to generate new parts of the world, the Java Garbage Collector started crying for all the mess it had to clean.</p>
|
||||
|
||||
<h2 id="other-image-here">Other image here </h2>
|
||||
|
||||
<p><strong>Greedy Meshing to overcome perfomance issues</strong></p>
|
||||
|
||||
<p>Speaking with some folks on the <a href="https://hub.jmonkeyengine.org">jMonkeyEngine Forums</a>, I got the advice to abandon the six-objects method I had been using, in favour of GreedyMeshing. As you can read from <a href="https://0fps.net/2012/06/30/meshing-in-a-minecraft-game/">in the 0fps article</a>, greedy meshing constructs a single mesh for the cubes faces with same texture that are next to each other.
|
||||
I didn’t really understand the maths that 0fps did, as I’m still in high school and I haven’t studies most of the concepts he used yet, but I was successfull in writing my own. It’s quite dumb code, as it’s mostly made of if statements and while cycle with mostly no Maths in it, but it works well, and I’m happy with it.</p>
|
||||
|
||||
<h2 id="other-image-here-1">Other image here </h2>
|
||||
|
||||
<p>[[This is a wirefram of a chunk mesh generated with greedy
|
||||
meshing]{.small}]{.small}</p>
|
||||
|
||||
<p><strong>Smooth world generation using Simplex Noise</strong></p>
|
||||
|
||||
<p>As I mentioned before, the early tests used a strange formula to generate less cubes on each layer as the position on the y-axis increased. This was abandoned in less than a couple of weeks, and I tried to have a smooth terrain generating ellipses starting for a center point, with the radius decreasing as the position on the position on the y-axis increased.
|
||||
But I started reading more and more about smooth pseudo-random number generation and I came across <a href="https://en.wikipedia.org/wiki/Perlin_noise">Perlin Noise</a>, which sounded really interesting.
|
||||
I tried to implement Perlin Noise by myself, but after a couple of unsuccesfull tries, I found this <a href="https://github.com/SRombauts/SimplexNoise/blob/master/references/SimplexNoise.java">Simplex Noise java implentation by SRombauts</a>.
|
||||
<a href="https://en.wikipedia.org/wiki/Simplex_noise">Simplex Noise</a> is computationally less expensive than Perlin Noise, which is can be really useful in this situation. I then adapted the Simplex Noise to my needs, added a couple of features for saving and loading the permutation table to and from file and the world generated was much more beatiful than before.</p>
|
||||
|
||||
<h2 id="other-image">Other image</h2>
|
||||
|
||||
<p>[[The first working test with Simplex Noise (left) and the first test
|
||||
ever with Simplex Noise (right)]{.small}]{.small}</p>
|
||||
|
||||
<p>At this point of the development, I decided to not use the <em>Cell</em> object
|
||||
anymore and replace them with simple integers inside the
|
||||
three-dimensional array. This saved up to 200MB of RAM when the player
|
||||
is still.</p>
|
||||
|
||||
<p><strong>Saving and Loading from file</strong></p>
|
||||
|
||||
<p>As I wanted to preserve the world when I closed the engine, I implemented a basic Chunk load/save system to save RAM by not keeping loaded <em>Chunks</em> that are very far apart from the player.
|
||||
This is also used to save the world when the game windows is closed and load it again when it’s reopened. The <em>Chunks</em> are saved in a plain text file, with each line corresponding to a single index of the 3d-array in the <em>Chunk,</em> with the x position, y position, z position and the id integer separated by spaces.</p>
|
||||
|
||||
<p>Along with the <em>Chunks,</em> also the <em>Simplex Noise Permutation Table</em> and the game settings are saved.</p>
|
||||
|
||||
<p>This system is absolutely bad, saving lots of <em>Chunks</em> requires even gigabytes of space on the disk, which is really insane.</p>
|
||||
|
||||
<p><strong>MultiThreading<em>,</em> Block Picking and Customization.</strong></p>
|
||||
|
||||
<p>Greedy Meshing and Loading <em>Chunks</em> from files require some time, which depends on the CPU and disk speed of the Computer. To remove this delay, which blocked the entire Main Thread of the game, I decided to load and generate <em>Chunks</em> in a separated thread, which doesn’t affect the main one.
|
||||
This makes the engine really smooth to run and the <em>Chunks</em> generating in front of you is really nice.</p>
|
||||
|
||||
<p>Implementing <em>Block</em> <em>Picking</em> alongside with <em>MultiThreading</em> was an hard time. jMonkeyEngine allows you to modify the scene only in the main thread, but I used to generate new <em>Chunks</em> in a secondary one.
|
||||
To solve this problem, I had to make the secondary thread only prepare the data for the <em>chunk</em> <em>mesh</em>, that the main thread uses to generate and show it.</p>
|
||||
|
||||
<p>Having the main features completed, it was time to implement some secondary ones. At first, during the making of the engine, I noticed I needed some way to make it more flexible to test different situations.
|
||||
So, I implemented lots of functions to do this: toggling debug messages, wireframe, test functions, changing the method used to generate the world, changing the size of the <em>Chunks</em> and of the world, adding new <em>block types</em> with just a couple of functions. This makes the engine way more flexible, also for other people, to use.</p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<p><strong>Conclusion</strong></p>
|
||||
|
||||
<p>At this point, I can declare my Voxel Engine completely working, and I’m really happy with it. During those years of development (I have to specify that I abandoned the development even for months during this time), I learned lots of new things about games and programming in general which helped me becoming a better programmer.</p>
|
||||
|
||||
<p>You can see all the history of the development on the <a href="https://github.com/EmaMaker/voxel-engine-jme3.git">github
|
||||
repo</a>.</p>
|
||||
|
||||
<p>But my learning journey isn’t finished yet, I still have tons of new things to learn.</p>
|
||||
</article>
|
||||
|
||||
<footer><p>
|
||||
Author: EmaMaker
|
||||
<a href="mailto:emamaker@tutanota.com">emamaker@tutanota.com</a>
|
||||
<br>
|
||||
This website is statically generated from markdown using <a href="https://git.alemauri.eu/alema/rivet">rivet</a>,
|
||||
a static website generator written in POSIX compliant sh by my dear friend <a href="https://alemauri.eu">Alessandro Mauri. Check him out!</a>
|
||||
<br>
|
||||
This website is hosted on Codeberg Pages. <a href="https://codeberg.org/EmaMaker/pages>Feel free to check out the sources</a>
|
||||
</p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
Binary file not shown.
After Width: | Height: | Size: 92 KiB |
Binary file not shown.
After Width: | Height: | Size: 178 KiB |
Binary file not shown.
After Width: | Height: | Size: 217 KiB |
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url><loc>/projects/voxelengine.html</loc></url>
|
||||
<url><loc>/projects/googlemeetbot.html</loc></url>
|
||||
<url><loc>/events/makerfaire2017.html</loc></url>
|
||||
<url><loc>/events/index.html</loc></url>
|
||||
<url><loc>/projects/index.html</loc></url>
|
||||
<url><loc>/notes/voxel.html</loc></url>
|
||||
<url><loc>/index.html</loc></url>
|
||||
<url><loc>/projects/spqr.html</loc></url>
|
||||
<url><loc>/notes/index.html</loc></url>
|
||||
</urlset>
|
|
@ -0,0 +1,172 @@
|
|||
/* GLOBAL */
|
||||
:root {
|
||||
--bg: #282828;
|
||||
--bg-code: #1d2021;
|
||||
--bg-alt: #32302f;
|
||||
--fg: #ebdbb2;
|
||||
--fg-code: #fbf1c7;
|
||||
--fg-alt: #d5c4a1;
|
||||
--fg-link: #d79921;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bg);
|
||||
color: var(--fg);
|
||||
max-width: 920px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
html {
|
||||
/* background-color: #696969;*/
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
article {
|
||||
padding-bottom: 2rem;
|
||||
border-bottom: 1px solid var(--fg);
|
||||
}
|
||||
|
||||
/* TABLES */
|
||||
table, th, td {
|
||||
border-collapse: collapse;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: left;
|
||||
width: 70%;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 1px solid var(--fg);
|
||||
}
|
||||
|
||||
tr:nth-child(odd) {
|
||||
background-color: var(--bg-alt);
|
||||
}
|
||||
|
||||
/* CODE */
|
||||
pre {
|
||||
background-color: var(--bg-code);
|
||||
color: var(--fg-code);
|
||||
font-size: medium;
|
||||
font-family: monospace;
|
||||
tab-size: 8;
|
||||
padding: 4px;
|
||||
}
|
||||
/*
|
||||
:not(pre) > code {
|
||||
background-color: #f9f4d7;
|
||||
color: #504945;
|
||||
}
|
||||
*/
|
||||
|
||||
/* LISTS */
|
||||
li {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
ol, ul {
|
||||
margin-left: 8%;
|
||||
padding-left: 0px;
|
||||
}
|
||||
|
||||
::marker {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* PARAGRAPHS */
|
||||
p {
|
||||
font-size: medium;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
/* HEADINGS */
|
||||
h1, h3, h5 {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
h2, h4, h6 {
|
||||
background-color: var(--bg-alt);
|
||||
}
|
||||
|
||||
h1 { font-size: xx-large; }
|
||||
h2 { font-size: x-large; }
|
||||
h3 { font-size: large; }
|
||||
h4, h5, h6 {
|
||||
font-size: medium;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* LINKS */
|
||||
a {
|
||||
color: var(--fg-link);
|
||||
}
|
||||
|
||||
/* FOOTER */
|
||||
footer {
|
||||
border: 1px solid var(--fg);
|
||||
margin-top: 5rem;
|
||||
}
|
||||
|
||||
footer p {
|
||||
font-size: x-small;
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* HEADER */
|
||||
#thumb {
|
||||
border-radius: 50%;
|
||||
bottom: 0;
|
||||
height: auto;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
right: 0;
|
||||
top: 0;
|
||||
position: absolute;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#thumb-container {
|
||||
float: left;
|
||||
height: 80px;
|
||||
padding-right: 40px;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
}
|
||||
@media (max-width: 550px) {
|
||||
#thumb-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#links {
|
||||
float: left;
|
||||
overflow: vsible;
|
||||
}
|
||||
|
||||
#links a {
|
||||
font-weight: bold;
|
||||
letter-spacing: normal;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
header {
|
||||
border: 1px solid var(--fg);
|
||||
font-size: medium;
|
||||
height: 80px;
|
||||
line-height: 80px;
|
||||
text-align: left;
|
||||
overflow: auto;
|
||||
}
|
Loading…
Reference in New Issue