<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>\o/</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/" />
    <link rel="self" type="application/atom+xml" href="http://erleuchtet.org/atom.xml" />
    <id>tag:erleuchtet.org,2008-03-14://3</id>
    <updated>2011-06-16T11:50:20Z</updated>
    
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.35-en</generator>

<entry>
    <title>white one - Making of</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2011/06/white-one.html" />
    <id>tag:erleuchtet.org,2011://3.94</id>

    <published>2011-06-15T21:54:28Z</published>
    <updated>2011-06-16T11:50:20Z</updated>

    <summary>white one is my first 4k intro and my first serious demoscene production (as far as something like that can be serious). I&apos;m new to C coding and to sizecoding in particular, so there were a lot of things to...</summary>
    <author>
        <name>cupe</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[<p><strong>white one</strong> is my first 4k intro and my first serious demoscene production (as far as something like that can be serious). I'm new to C coding and to sizecoding in particular, so there were a lot of things to be learned which I'll try to summarize here. Download and run the <a href="http://releases.never.de/2010/tum/never-white_one-partyversion.zip">executable</a> (nvidia only, sorry) or watch the video capture first:</p>

<p><object width="640" height="390"><param name="movie" value="http://www.youtube-nocookie.com/v/dfq1dPlGs0A?fs=1&amp;hl=de_DE&amp;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/dfq1dPlGs0A?fs=1&amp;hl=de_DE&amp;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="390"></embed></object></p>

<p>A 4k intro is a executable file of at most 4 kilobytes (4096 bytes) that generates video and audio. That is, it puts something moving on your screen and something audible on your speakers. The finished product runs for a few minutes, has some coherent theme and design and ideally, sound and visual effects complement each other. On top of that, it's a technical challenge: It's impossible to store 3D models, textures or sound samples in 4 kilobytes, so you have to generate these things at runtime if you need them. </p>

<p>Overwhelmed by the impossibility of all this I started messing around.</p>

<p>I had been lurking on a few demoparties, but never released anything nontrivial - i do know some OpenGL, but i am normally coding Lisp which tends to produce executables that are measured in megabytes. Obviously, that had to change if i wanted to contribute a small intro. Playing with the GL Shading Language had always been fun for me, so it was clear that something shader-heavy was the only option. And I had some experience with C from microcontroller hacking.</p>

<p>When some friends of mine implemented a cellular automaton on the Fragment Shader in summer, I took their code and started messing with the shader. 
A cellular automaton implements a function on a grid of cells (here: pixels). The function takes the whole grid as input and produces a single pixel's value as output. To get one new frame, it has to be applied once for each pixel, using the previous frame as input.</p>

<p>A very simple function of that kind would, for example, assign to each pixel the value of its left neighbour, thus moving the whole image to the right by one pixel with each frame.</p>

<p><a href="http://erleuchtet.org/foobar.png"><img alt="foobar.png" src="http://erleuchtet.org/assets_c/2011/06/foobar-thumb-230x460-407.png" width="230" height="460" class="mt-image-left" style="float: left; margin: 0 20px 20px 0;" /></a></p>

<p><strong>The Shader</strong></p>

<p><em>(you might want to skip this section if you are more interested in how to make 4k intros in general)</em></p>

<p>First, i experimented with a function that looked like this: </p>

<blockquote>
<pre><code>1. Look up this pixel's current color.
2. Convert it to HSV colors. 
3. Use the Hue value as an angle and walk (dist\_s\*S + dist\_v\*V + dist\_sv\*S\*V + dist\_base) pixels into that direction in the image, where the dist\_something values are arbitrarily chosen by me.
4. Look up the color value from there and output this as the pixel's new color.
</code></pre>
</blockquote>

<p>I made a small program that allowed me to play with the four parameters. Depending on the choice of the four parameters, interesting yet ugly things happened, e.g. solid-color patches would move about the screen until they collided and merged to a single color or something vagueley resembling smoke would appear.</p>

<p>I realized i wanted some more features and added new parameters to adjust the output color in HSV color space, e.g. rotate the color wheel by incrementing H, decrease/increase the saturation S and darken/lighten the image by modifying V. 
A new parameter for weighted averaging between the old and the new image was also introduced. Interestingly, instead of using values between 0 and 1 for this blending, i ended up using values below 0 or above 1 for many of the more interesting effects :)</p>

<p>The next addition was a parameter to control smoothing the image. A value of 0 would mean no smoothing, 1 would mean a standard smoothing kernel of [[0 1 0] [1 4 1] [0 1 0]]. We are now only one more parameter away from the first effect that actually made it into the final intro which is also the first one on the screen:</p>

<p>(This will be the last time i bore you with concrete numbers)</p>

<blockquote>
<pre><code>smooth: -2.400000
dist_base: 1.400001
dist_s: 3.099999 
dist_v: -1.900000
dist_sv: -2.400000
mix_bias: -0.480000 (alpha blending between frames)
h_cycle: 0.020000 (cycle the color wheel by a small amount)
rotate: 0.001000
</code></pre>
</blockquote>

<p>As you can see, the smoothing parameter is outside its normal range of [0,1] as well and the kernel that is defined this way looks a lot like a sharpening kernel. If you look closely at the very beginning you can see checkerboard-like pixels in the center that are due to this sharpening. The one missing parameter, called "rotation", rotates the input image by a certain angle before reading from it - or so i thought. I discovered later that i had used the rotated image just for the first read (the one determining in which direction to walk for the second read), but the second read was on the unrotated image. When i fixed this, everything became a lot less interesting, so i kept the bug.</p>

<p>In the periphery of the image it gets blurred by rotating it less than a full pixel and OpenGL's bilinear texture-filtering blending neighbouring values. If you look very closely in the final 1080p production, you can see four areas where the rotation is just about one pixel and the checkerboard pattern re-emerges. I also introduced a parameter for zooming that works just like the rotation parameter (i.e. it is broken as well).</p>

<p>The last parameter controls alpha blending of the final image with an additional image. The reason i had to do this is that some effects can get stuck unpredictably: Once the screen is of a solid color it will stay a solid color forever. I needed a way to re-introduce some variation in the image to get the effects started again in this case. Naively, I thought there would be enough space in the 4 kilobytes to render some primitive geometry (procedural trees and such) so I could use those as a starting point for a LSD trip. 
In the end the rendered geometry just became a rotating white "1" (|) that is only visible in some effects. Anyway, now there are two inputs: the last frame and some rendered geometry.</p>

<p>Here is the final shader code in GLSL. The rgbToHsv and hsvToRgb functions are not pasted here and behave as you would expect ;)</p>

<iframe src="http://pastebin.com/embed_iframe.php?i=gm55LxzZ" height=350px style="border:none;width:100%"></iframe>

<p>So this is basically the heart of the intro. It is arguably less then readable since we had compressed the code a bit already. GLSL code must be given as a string to OpenGL and is compiled by the graphics card driver, so the whole shader code has to be present in the executable. Later, all variables and functions would be renamed to one-character names and so on, making it even less readable.</p>

<p>After some time i had collected about 70 different parameter sets that i had found interesting, many of them similar and some ugly. My eyes hurt. Here are some more examples:</p>

<p><a href="http://erleuchtet.org/bla-1.png"><img alt="bla-1.png" src="http://erleuchtet.org/assets_c/2011/06/bla-1-thumb-300x300-399.png" width="300" height="300" class="mt-image-none"/></a><a href="http://erleuchtet.org/bla-3.png"><img alt="bla-3.png" src="http://erleuchtet.org/assets_c/2011/06/bla-3-thumb-300x300-401.png" width="300" height="300" class="mt-image-none"  /></a></p>

<p><a href="http://erleuchtet.org/bla-4.png"><img alt="bla-4.png" src="http://erleuchtet.org/assets_c/2011/06/bla-4-thumb-300x300-403.png" width="300" height="300" class="mt-image-none"  /></a><a href="http://erleuchtet.org/wellen_almost_converged.png"><img alt="wellen_almost_converged.png" src="http://erleuchtet.org/assets_c/2011/06/wellen_almost_converged-thumb-300x300-405.png" width="300" height="300" class="mt-image-none" /></a></p>

<p><strong>The Rest</strong></p>

<p>Now that the shader functionality was fixed (any change would invalidate many of the 70 precious effects), i needed to wrap it in a 4k executable, get some music and make some kind of timeline. Fortunately there are now some nice tools that help the aspiring demo coder with these tasks. For the music, many 4k intros today use 4klang as a synthesizer. 4klang is designed for 4k intros and produces an object file containing the synth, the intruments as well as music data that you can link against. I also found <a href="http://iquilezles.org/www/material/isystem1k4k/isystem1k4k.htm">iq's 4k framework</a> which is more of a collection of frameworks for different kinds of 1k and 4k intros. I just took the one for OpenGL shader-on-a-quad intros and started reading its code, figuring out how it works. The third tool is <a href="http://www.crinkler.net/">Crinkler</a>, a size-optimizing and compressing linker that replaces/calls Visual Studio's builtin linker and is probably used in 95% of today's 4k and 64k intros on windows. Since Crinkler is Windows-specific, now was the time to switch operating systems and start Visual Studio for coding on Windows for the first time in ten years or so. After a few nights i even stopped using emacs shortcuts.</p>

<p>In the meantime i had coaxed my <a href="http://umruehren.soup.io">brother</a> into composing music. While he familiarized himself with the 4klang workflow (using <a href="http://openmpt.org/">OpenMPT</a> for composing) I continued experimenting with the framework. So now we had become a team of two and kept each other updated while i was distracted for a few months by my last exam. This is how it went for him:</p>

<p><strong>Music</strong></p>

<p>Clemens speaking. So, to be honest, I didn't know at all what I got myself into - I'm new to music making, never seen a tracker or stack-based synthesizer before and because I live far far away, I knew nothing about the visuals but a few old screenshots.</p>

<p>To my surprise, I had a lot of fun. Once you understand stack based synthesis, 4klang is  straightforward and gives you really tight control of the sound - you just play and create. There's also not much of an interface to get into your way and I miss that when going back to the pseudo-analogue button soup of Logic or Ableton.
But since it's so open, you've got to play with it for a while to find out what you can do.</p>

<ul>
<li>Don't be afraid of 4klang's store unit, because that could well be the most awesome little feature of this synth. It allows you to store the current top value of the stack in (almost) any parameter of (almost) any other unit. That's a simple concept, but it really pays off to follow alcatraz' advice to go crazy with it.
You can build multi-purpose instruments that behave differently based on the current pitch. Or get evolving sounds, by adding LFOs or envelope units to provide you with control values that change on a per-note-timescale. Then modulate the parameters of these generators, again, with the current pitch or with a dedicated control instrument to get evolving <em>and</em> pitch-dependent sounds. Add more meta levels. Try and see what happens if you filter the control values before feeding them into Store units. And so on. It's really a lot of fun.</li>
</ul>

<p><object height="81" width="100%"> <param name="movie" value="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11921809"></param> <param name="allowscriptaccess" value="always"></param> <embed allowscriptaccess="always" height="81" src="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11921809" type="application/x-shockwave-flash" width="100%"></embed> </object>  <span><a href="http://soundcloud.com/umruehren/4klang-drums">(4klang) Drums</a> by <a href="http://soundcloud.com/umruehren">umruehren</a></span> </p>

<p><object height="81" width="100%"> <param name="movie" value="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11922011"></param> <param name="allowscriptaccess" value="always"></param> <embed allowscriptaccess="always" height="81" src="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11922011" type="application/x-shockwave-flash" width="100%"></embed> </object>  <span><a href="http://soundcloud.com/umruehren/4klang-gebrumml-gbrumml">(4klang) Gebrumml Gbrumml</a> by <a href="http://soundcloud.com/umruehren">umruehren</a></span> </p>

<ul>
<li><p>Store the output of your main envelope into said envelope's own gain parameter. I'm still not convinced that this should work, but it <em>will</em> add a lot of punch to the sound, e.g. for a bass drum.</p></li>
<li><p>I had some problems with phase shifts (for instruments that made heavy use of the reverb unit), resulting in louder-than-usual click noises between notes. In that case, you can get quite far by hand-adjusting the phase and/or detune of the offending oscillators via control instruments... for each note change. Note the glitches:</p></li>
</ul>

<p><object height="81" width="100%"> <param name="movie" value="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11925208"></param> <param name="allowscriptaccess" value="always"></param> <embed allowscriptaccess="always" height="81" src="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11925208" type="application/x-shockwave-flash" width="100%"></embed> </object>  <span><a href="http://soundcloud.com/umruehren/4klang-jell-o">(4klang) jell-o</a> by <a href="http://soundcloud.com/umruehren">umruehren</a></span> </p>

<p>So now for the really difficult part: What kind of sound will match the visuals? And how do you write write music, anyway? Sadly, there's not much to say about my creative process - Because, obviously, when I say "creative process" I mean "messing around until something works or time's up". 
At least, I managed decide on <em>"minimalistic but full of little fuzzy things"</em> as a general aim before I started. But what does that even mean? 
So, instead of planning, I built some 4 or 5 proto-tracks that all went into the trash can for very good reasons (but each one was a necessary step) until suddenly, well, time was up and we stuck to the last one. </p>

<p>I'm almost sure that that is the only correct way of doing things.</p>

<p><object height="81" width="100%"> <param name="movie" value="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11921925"></param> <param name="allowscriptaccess" value="always"></param> <embed allowscriptaccess="always" height="81" src="http://player.soundcloud.com/player.swf?url=http%3A%2F%2Fapi.soundcloud.com%2Ftracks%2F11921925" type="application/x-shockwave-flash" width="100%"></embed> </object>  <span><a href="http://soundcloud.com/umruehren/4klang-mod4">(4klang) Mod4-</a> by <a href="http://soundcloud.com/umruehren">umruehren</a></span> </p>

<p><strong>Music size optimization</strong></p>

<p>At about two weeks before the party, I had a track ready. But at 2.5k compressed (about 500 bytes non-negotiable 4klang baseline + 1k for instruments + something short of 1k of note values) that was completely unusable for our 4k. So something had to go. </p>

<p>The final track weighed in at about 1.5k compressed, which means I trashed a kilobyte of instrument definitions and note values. The price for that is of course a reduction of the richness-of-sound (you delete less important instruments, merge instruments, simplify instruments) and reduction of variety (reduce the number of different substrings in each instrument track, delete less brilliant parts and generally repeat more stuff). Strangely, I think if anything, the track got better because of the size constraints. </p>

<p><strong>Mastering</strong></p>

<p>There's just one big regret I have: We should have tested the track on a range of different speakers before submitting, because obviously the party PA behaved differently from the 
Nubert HiFi speakers we used for the final "mastering". Using the HiFi, I evened out a lot of high frequencies a few days before the party, and the result was mud. That's probably a rookie mistake so don't do it.</p>

<p>One last thing. I've read a few comments by non-coder musicians who complained that 4klang wasn't nice and easy enough - you're just being lazy. All the hard work has been done for you. So grab the chance if someone asks you to learn this stuff - it's a lot of fun and kind of addictive. </p>

<p>So much for the music.</p>

<p><strong>Finishing</strong></p>

<p>I got 4klang plugged into the framework with halcy's help, which proved more difficult than i had expected because the executables i first compiled (even the 4klang example) produced weird glitches on my machine, but not on other machines... Eventually we got it working (without understanding the problem) while my brother's musical output became better and better. This was about a month before <a href="http://tum-party.net/">tUM</a>, the demoparty where we wanted to release the yet-unnamed intro.</p>

<p>Again with the help of some friends at <a href="https://entropia.de">entropia</a> i got the basic functionality of the linux feedback-explorer ported into the framework. I eliminated many of the 70 original effects, reducing them to about 20, and identified some unnecessary parameters. Still, 20 times 14 float values of four bytes each would be a bit too much to fit in the 4 kilobytes together with the shader, the music, the C glue and the yet-imaginary timeline. I edited the table by hand and with python tools written for the purpose to try and find a compact representation. Many of the values where precision was not that important were merged to the same value so that crinkler could compress better. Also they were mapped to 16bit integers and restored at runtime which did hurt precision, but did not destroy the effects if one chose the right mapping and the few really delicate values ended up being restored close to their original value. The parameter table now took up about 500 bytes and compressed to about 200 bytes which was okay. The whole thing, including the beta music, was 4.8 kilobytes - there were three weeks to go and no timeline or concept yet.</p>

<p>We met around christmas at our parents' house and spent hours creating a sequence of the effects. We introduced a parameter flag to control weather one effect's parameters would be blended into the next effect's parameters while it was running or if the transition would be abrupt. We made a timeline. Syncing sound and visuals late at night proved harmful to sleep quality and after the first night of dreaming of spirals we forced us to take some breaks every few hours.  The rendered geometry was cut from fancy twisting spiral-ribbons to the single white quad. We finally arrived at a size of 4200 bytes when we headed for my place in Karlsruhe, right next to where tUM takes place. The intro had even got our grandmother's approval over christmas, which is not something that many people can say about their LSD-themed 4k intros.</p>

<p>At the partyplace we tested the beta version on the compo machine - it worked. Relaxed, we plucked a few more bytes here and there, did some last syncing, hid the mouse cursor, made executables for the various resolutions and won the 4k competition. Here is the live footage of the crowd going wild:</p>

<p><object width="640" height="390"><param name="movie" value="http://www.youtube-nocookie.com/v/jPRUEeCM_o4?fs=1&amp;hl=de_DE&amp;hd=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube-nocookie.com/v/jPRUEeCM_o4?fs=1&amp;hl=de_DE&amp;hd=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="390"></embed></object></p>

<p>Finally, after ten years of being intimidated by the demoscene, we started to see sceners no longer as godlike, but as talented and motivated people. Had we learned this lesson earlier, we would have started making demos years ago.</p>

<p>Download the original 4k executable from <a href="http://www.pouet.net/prod.php?which=56459">pouet</a>. We didn't bother making the source pretty, but you can <a href="http://erleuchtet.org/~cupe/permanent/white_one_partyversion_src.tar.gz">have a look</a> if you want.</p>

<p><small>All content made by Johann Korndörfer and Clemens Korndörfer. Released CreativeCommons 3.0 ShareAlike.</small></p>
]]>
        

    </content>
</entry>

<entry>
    <title>Multitouch360</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2010/08/multitouch360.html" />
    <id>tag:erleuchtet.org,2010://3.89</id>

    <published>2010-08-21T20:59:35Z</published>
    <updated>2010-08-27T14:27:48Z</updated>

    <summary><![CDATA[ &nbsp;- a Platform for Interactive Art Installations Multitouch360 is a project by Johann Korndoerfer and Thorsten Blum that aims at creating a hemispherical multitouch display. It has now officially reached some degree of "finished", meaning that all essentials are...]]></summary>
    <author>
        <name>cupe</name>
        
    </author>
    
        <category term="games" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="multitouch" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="programming" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[

<p><a href="http://erleuchtet.org/hand.jpg"><img alt="hand.jpg" src="http://erleuchtet.org/assets_c/2010/08/hand-thumb-300x205-394.jpg" class="mt-image-right" style="float: right; margin: 0pt 0pt 20px 20px;" height="204" width="300" /></a></p>

<br />
<p><i>&nbsp;- a Platform for Interactive Art Installations</i></p><br />

<p><strong>Multitouch360</strong> is a project by Johann Korndoerfer and Thorsten Blum that aims at creating a hemispherical multitouch display. It has now officially reached some degree of "finished", meaning that all essentials are working, no cheap workarounds remain in either hardware or software and the software framework is capable of letting anyone code cool stuff.</p>

<p>Watch the short video below:</p>

<p><iframe src="http://player.vimeo.com/video/14314682" frameborder="0" height="308" width="546" ></iframe></p>

<p>This is my debug application running on Multitouch360, showing a wire hemisphere along with camera calibration markers and visualizing touch events. As you can see, touch recognition works reasonably well.</p>
<p><strong><big>How does it work?</big></strong></p>
<p>
<a href="http://erleuchtet.org/camera.jpg"><img alt="camera.jpg" src="http://erleuchtet.org/assets_c/2010/08/camera-thumb-400x301-386.jpg" class="mt-image-left" style="float: left; margin: 0pt 20px 20px 0pt;" height="188" width="250" /></a> We use a technique called FTIR (Frustrated Total Internal Reflection) to detect touches. This means that an infrared camera looks at the hemisphere from the inside. The picture to the left is what the camera sees - you can see a shadow from the hand and five bright points at the tips of the fingers. Those bright points are created by the users' fingers touching the outer acrylic hemisphere (called the Wave Guide). The Wave Guide is made of clear acrylic and flooded with infrared light from 288 infrared LEDs set in the rim. The IR light can't escape the acrylic except when it is touched by an object with a sufficiently large refractive index, like water or human skin. Thus, the infrared light enters the finger, gets scattered and can be picked up by the camera.</p><p><br /></p>

<p><a href="http://erleuchtet.org/full_dark_captions.JPG"><img alt="full_dark_captions.JPG" src="http://erleuchtet.org/assets_c/2010/08/full_dark_captions-thumb-350x358-388.jpg" class="mt-image-right" style="float: right; margin: 0pt 0pt 20px 20px;" height="306" width="300" /></a>Since you can't project anything onto clear acrylic, we needed a inner layer of matte acrylic (called the Diffusor) just inside the Wave Guide. This layer makes the bright points from the outer layer a bit blurry for the camera, but we would have done the blurring in software anyway. Using a mirror to save some space, we project a rendered image onto the Diffusor, again from below. You can see the whole setup in the image to the right.</p>

<p>The image that is projected onto the sphere gets distorted quite a bit, which has to be anticipated in software. The same applies for the other direction: touch locations have to be transformed back into 3d as well. Both the projection and the camera have to be calibrated, which can be done by clicking five positions with the mouse (calibrating the projector), then touching the same positions on the sphere (calibrating the camera). You can see a visualization of the gradient descent that solves the resulting optimization problem right at the beginning of the video above.</p>

<p><big><strong>The Software</strong></big></p>

<p>I made a nice little framework for Multitouch360 that lets you write multitouch applications. The debug application from the video above looks like this:</p>


<pre><p><code><strong>from</strong> multitouch360 <strong>import</strong> *

<strong>class</strong> DebugApplication(MultitouchApplication):

    <strong>def</strong> touch_down(<strong>self</strong>,touch):
        TouchIndicator(touch)    

    <strong>def</strong> touch_move(<strong>self</strong>,touch):
        <strong>pass</strong>

    <strong>def</strong> touch_up(<strong>self</strong>,touch):
        Explosion(touch.world_pos)

    <strong>def</strong> display(<strong>self</strong>):
        glutWireSphere(1,30,30)

DebugApplication()</code></p><p></p></pre>


<p>And this is it. You can define textures, buttons, etc. easily and the weird math you need for handling things on a sphere is taken care of.</p>

<p><strong><big>What do you do with it?</big></strong><br /></p><p><a href="http://erleuchtet.org/crowd_und_setup.jpg"><img alt="crowd_und_setup.jpg" src="http://erleuchtet.org/assets_c/2010/08/crowd_und_setup-thumb-300x400-390.jpg" class="mt-image-left" style="float: left; margin: 0pt 20px 20px 0pt;" height="374" width="280" /></a></p>

<p>First, <b><em>you</em></b> can do something with it. If you know some Python and OpenGL, you can code your own application. The Multitouch360 framework will simulate the hemisphere on any computer and you can click on a virtual version of it with your mouse. If you are interested in doing something with it and you are located near Karlsruhe, Germany, please let me know. Keep in mind that anything that runs on Multitouch360 must be tailored to the spherical layout - thinking in 2d will make you wish you had a flat table, but embracing the hemispherical form lets you do some things that are impossible otherwise: planets, star maps, boobs or eyes are some of the things that may come to life. Games that involve not seeing what your opponent is doing on their side are another obvious candidate.</p>

<p>Second, i have made a few very simple demo applications that are hardly more than a hello-world, but may show what's possible. Watch people play Global Thermonuclear War in the video below, incinerating whole countries by touching them. The only winning move is not to play. (Application written in about three hours.)</p>

<p<iframe src="http://player.vimeo.com/video/14314697" width="546" height="308" frameborder="0"></iframe></p>

<p><big<strong>Project State</strong></big><br /></p>

<p>Although there are a lot of other ideas for games or weird interactive installations, i am now starting to pursue other projects and apart from some maintenance, documentation and potentially helping you code something nice, the project is now finished for me.</p>

The project is also part of my subsidiary subject (Media Art) at Hfg Karlsruhe and has kindly been hosted by the Computer Graphics Department of the Karlsruhe University.

This post is also mirrored on the official <a href="http://multitouch360.com">Multitouch360 blog</a> where you can find more pictures of Thorsten and me building the thing.]]>
        
    </content>
</entry>

<entry>
    <title>Rendering a ridiculously large Buddhabrot</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2010/07/ridiculously-large-buddhabrot.html" />
    <id>tag:erleuchtet.org,2010://3.83</id>

    <published>2010-07-02T21:41:29Z</published>
    <updated>2011-10-19T10:10:51Z</updated>

    <summary>This article describes how to render a ridicuously large 500 Megapixel Buddhabrot with iteration depths in the range of millions. Lisp source included. Scroll down for the final image.Why would you want to do this? To have it printed and...</summary>
    <author>
        <name>cupe</name>
        
    </author>
    
        <category term="graphics" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="lisp" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="programming" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[<p>This article describes how to render a ridicuously large 500 Megapixel Buddhabrot with iteration depths in the range of millions. Lisp source included. Scroll down for the final image.<br /></p><p><br /><a href="http://erleuchtet.org/buddhabrot_small_detail.jpg"><img alt="buddhabrot_small_detail.jpg" src="http://erleuchtet.org/assets_c/2010/07/buddhabrot_small_detail-thumb-250x318-365.jpg" class="mt-image-left" style="float: left; margin: 0pt 20px 20px 0pt;" height="318" width="250" /></a>Why would you want to do this? To have it printed and on your wall, of course (see pictures below).<br /></p><p>I will begin by outlining the general idea of the Buddhabrot (see the <a href="http://en.wikipedia.org/wiki/Buddhabrot">Wikipedia article</a> for more), then talk about my optimizations and rendering choices.</p><p><b><font style="font-size: 1.25em;">The Buddhabrot</font></b><br /></p>You typically render a Buddhabrot by choosing a set of starting points in the complex plane (i will call them "samples" from now on), run each sample c trough the iteration z_k+1 = z_k^2 + c with z_0 = 0+0i and for those that grow very large after some time (i.e. those that are outside the Mandelbrot Set) remember all the z_k that have been visited during the iteration. All those visited points from all the escaping samples form a point cloud in the complex plane that is usually called a Buddhabrot when visualized.<br /><p><br />You need a maximum iteration depth n (sometimes called the Dwell Limit) because many samples will be within the Mandelbrot Set and you would run the iteration indefinitely for those. Whenever the maximum iteration depth is reached, the sample is considered to be inside the Mandelbrot set - although it possibly isn't and after another 1000 Iterations it would have escaped. There is no way to be sure.</p><p>We now consider only those samples "good" whose iteration escaped before reaching the maximum iteration depth, i.e. those who are definitely outside the Mandelbrot Set. Each good sample gives a set of points whose magnitude is equal to the number of iteration steps i that it took for us to find out that it was outside the Mandelbrot Set. Sometimes this is a very small number like 2 or 3, but samples nearer to the border of the Mandelbrot Set take much longer. A sample can take thousands or millions of iterations before escaping, thus leaving a much larger footprint in the resulting point cloud. It seems that for each Natural Number n there is a sample that takes at least n iteration steps, although for higher values of n it becomes harder and harder to find one.</p><p><b><font style="font-size: 1.25em;">Deep Iteration</font></b><br /></p><p>It has been observed by many people that just rendering the Buddhabrot like this - using all the escaping samples' visited points - gives a nebula-like image but that a more interesting image can be made by considering only those samples as "interesting" whose iteration time i exceeds some minimum iteration time k with k &lt; n. For example, you could use k = 1000 and n = 10000, i.e. keep only those samples that do not escape before their 1000th iteration but do escape before their 10000th iteration. If you look at one of those more deeply iterated good samples' visited path in the complex plane you will note some pattern: it forms some kind of orbit, sometimes some kind of circle or a set of circles or other shapes. I have no idea why the orbits are shaped this way and i don't know if anyone else does. Here is a part of the orbit of the sample -0.9114822433916717 + 0.2523940788714053i, for example (containing nearly five million points):</p><p><a href="http://erleuchtet.org/orbit.png"><img alt="orbit.png" src="http://erleuchtet.org/assets_c/2010/07/orbit-thumb-400x315-368.png" class="mt-image-none" style="" height="315" width="400" /></a></p><p>Incidentally, all interesting samples like this one are located very very close to the border of the Mandelbrot Set and make good targets to zoom into with your favourite fractal explorer. Try it.</p><p>Since the longer orbits look nice we will try to find only "interesting" samples that take a long time to finally escape. There have been several approches to find them. The most obvious one is of course just choosing a sample randomly and seeing how it goes, which means throwing away something like 99.999% of them. You could also use a regularly spaced grid of samples which basically means the same. The interesting samples are all located near the Mandelbrot Set's border, so there must be some spatial pattern to their distribution which might help us find them. If you ever played around with the Set a bit you probably know that the border is infinitely long and calling it "complex" is a bit of an understatement, but surely we can do better than just randomly sample the plane?</p><p><b><font style="font-size: 1.25em;">Optimization</font></b></p><p><a href="http://erleuchtet.org/Mandelbrot_Set_%E2%80%93_Periodicities_coloured.png"><img alt="Mandelbrot_Set_-_Periodicities_coloured.png" src="http://erleuchtet.org/assets_c/2010/07/Mandelbrot_Set_%E2%80%93_Periodicities_coloured-thumb-300x270-371.png" class="mt-image-right" style="float: right; margin: 0pt 0pt 20px 20px;" height="270" width="300" /></a></p><ul><li>Rejecting all samples from within the two biggest parts of the Mandelbrot Set, the "Main Cardioid" and the circular "Period-2-Bulb", is a must-have. This simple check removes a large amount of all the points in the Set which are very costly because they will iterate until the dwell limit is reached. I just used the <a href="http://en.wikipedia.org/wiki/Mandelbrot_set#Optimizations">formula</a> from the Wikipedia article. The areas removed by this test are shown in red on this image of the Mandelbrot Set (my output images are rotated clockwise by 90 degrees, don't get confused):</li><li>People have also used the Metropolis-Hastings Algorithm, considering the mapping c -&gt; i a propability density function. The method is especially useful for rendering a small detail of the bigger image, but does not work too well for the whole image with very big values of k. I kept finding many interesting samples with it, but their orbits turned out to be very similar because several good samples that are very close to each other produce orbits that are almost identical - giving an image of a single blurred orbit. I increased the mutation distance enough to produce sufficiently distinctive orbits, but then the speedup was gone. In the end i didn't use this method. Probably it is more useful for rendering the "normal" Buddhabrot or a detail of it without the minimum iteration constraint.</li><li>To partly remove some of the costly larger areas (like the non-circular bulbs labeled "3" and up in the image above) from within the Set i divided the plane into rectangular cells and chose random samples only from those cells that contained some part of the border of the Mandelbrot Set. Depending on the cell grid resolution and the iteration depth this gave a speedup of 3 to 8.<br /></li></ul><p><b><br /></b></p><p><b><font style="font-size: 1.25em;">"The"&nbsp; Buddhabrot</font></b><a href="http://erleuchtet.org/buddhabrot_symmetry.jpg"><img alt="buddhabrot_symmetry.jpg" src="http://erleuchtet.org/assets_c/2010/07/buddhabrot_symmetry-thumb-250x393-374.jpg" class="mt-image-right" style="float: right; margin: 0pt 0pt 20px 20px;" height="393" width="250" /></a></p><p>Since we still choose our samples randomly, every rendering will look different - depending on which orbits your random search finds. There is no "the" Buddhabrot (see Melinda's comment below - rendering for an infinite amount of time yields "the" Buddhabrot). This also means that the image is not symmetic on the small scale which is a good thing if you ask me. You could of course get a symmetric image of the same quality in half the time by mirroring it, but i think it's worth waiting for the asymmetric one. On the right is a part of the final rendering that exhibits superficial symmetry, but is composed of asymmetric orbits. Click it to view this detail in the final resolution.<br /></p><p>If i had had my renderer run for much longer (maybe a week or a month), more and more orbits would have shown up, occluding each other and finally blurring the whole thing into the standard nebula-like buddhabrot. The key is to render just long enough until a sufficient amount of orbits have appeared and then stop.</p><p><b><font style="font-size: 1.25em;">Lisp Implementation</font></b></p><p>The renderer is written in Common Lisp which is not your classic number crunching language. If the goal was to do it as fast as possible, you'd probably end up doing it in C with inline assembly or on the GPU. On the other hand, i had never really optimized any lisp code to the limit and wanted to do just that: see how far you can get. One long night of low-level optimization at <a href="http://entropia.de/">entropia</a> with the help of some friends later there was is only a factor of 2 left compared to the C implementation that one entropian made. Which is quite okay, considering the cumulative speedup of about 2000 compared to my first implementation. Trading of sbcl's builtin complex numbers for traditional pairs of floats, declaring all types, working in-place instead of on the stack, considering cache efficiency, prompting usage of inline arithmetic instead of jumps to costly sbcl functions, etc. gained us a factor of about 3 to 5 while the big rest was due to the algorithmic improvements.<br /></p><p>The renderer uses double-floats throughout. I think i can safely say that the orbits' shapes are not due to cumulative floating-point errors (which i had suspected at some time) because tiny variations in the starting value usually do not produce significantly different orbits. Orbits are not chaotic systems.</p><p>Since tracing the few good samples is quite cheap compared to finding them, the renderer first multithreadedly collects some good samples by randomly sampling from the grid cells (see optimizations above) and only afterwards processes them to keep track of their jumping around on the complex plane. Their path is recorded in a big 16bit greyscale image which is repeatedly written to disk.</p><p><b><font style="font-size: 1.25em;">Postprocessing, Color and Noise</font></b><br /></p><p>Converting this greyscale HDR image to a LDR image with color has to be done by hand which is a nontrivial task for most image manipulation programs because 20000x25000 is not exactly your standard image resolution. Gimp and Cinepaint both crash or freeze (and Gimp can't handle 16-bit images), but Photoshop worked for me. I also cheated a bit by gently surface-blurring the image, removing some noise.</p><p>The noise is the only reason you need the really large iteration depths in the range of millions that i used. If you increase both the minimum iteration time and the maximum iteration limit, your orbits will consist of more and more points, allowing you to choose a higher resolution. If, on the other hand, you get less than, say, five hits per pixel in the darker regions of the orbit you will start to notice that some pixels may get only two hits and their neighbour pixel may get ten hits which will be visible as noise in the output image. If you iterate more deeply, this effect evens out and the signal-to-noise ratio increases. To remove noise, you can always downscale the output image or, as i did, selectively blur the image a bit to improve the look of the noisy areas.<br /><br />For the output image that i consider the most successful one i used a minimum iteration time of 1000000 and a maximum iteration depth of 5000000. it took about 16 hours on my university's 8-core Xeon machine which i abused for this task overnight.</p><p><font style="font-size: 1.25em;"><b>Results</b></font></p><p><a href="http://erleuchtet.org/buddhabrot_medium.jpg">Here</a> is a scaled version of about 5000x6000 pixels for your firefox's non-crashing convenience.<br /></p><p><a href="http://erleuchtet.org/buddhabrot_medium.jpg"><img alt="buddhabrot_medium.jpg" src="http://erleuchtet.org/assets_c/2010/07/buddhabrot_medium-thumb-700x890-375.jpg" class="mt-image-center" style="text-align: center; display: block; margin: 0pt auto 20px;" height="890" width="700" /></a></p><p><a href="http://erleuchtet.org/buddhabrot_print.jpg"><img alt="buddhabrot_print.jpg" src="http://erleuchtet.org/assets_c/2010/07/buddhabrot_print-thumb-200x270-384.jpg" class="mt-image-right" style="float: right; margin: 0pt 0pt 20px 20px;" height="270" width="200" /></a></p>
<p>I am quite satisfied with the digitally printed one as well, although some of the darker reds lose their saturation.<br /></p><p>Do <b>not</b> open the <a href="http://erleuchtet.org/%7Ecupe/permanent/buddhabrot_large.jpg">large image</a> in your browser. It is a 93MiB JPG file of 20000x25000 pixels which consumes 1.5 GiB of RAM when opened. Don't try this at home. I warned you.<br /><br />You can also have a look at the <a href="http://erleuchtet.org/buddhabrot-1.0.tar.gz">Lisp source</a>.<br /><a href="http://erleuchtet.org/buddhabrot-1.0.tar.gz"><br /></a></p><font style="font-size: 0.64em;">Images created by Johann Korndoerfer (cupe) and released </font><font style="font-size: 0.64em;">CC-Attribution 3.0 Germany</font><font style="font-size: 0.64em;">, except the original Mandelbrot bulb image by Wikipedia user Hoehue. </font>


]]>
        

    </content>
</entry>

<entry>
    <title>Talk: Computer Graphics, Part 1</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2009/01/talk-computer-graphics-part-1.html" />
    <id>tag:erleuchtet.org,2009://3.25</id>

    <published>2009-01-15T00:23:42Z</published>
    <updated>2009-01-17T18:11:20Z</updated>

    <summary>As promised earlier, i gave a talk at entropia in december. I tried to touch many of the non-hardware-oriented topics in computer graphics, with a focus on those that are interesting (to me, at least) and easy to explain without...</summary>
    <author>
        <name>cupe</name>
        
    </author>
    
        <category term="graphics" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="talks" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[<p>As promised <a href="http://erleuchtet.org/2008/11/latex-beamer-markup-less-sucka.html">earlier</a>, i gave a talk at <a href="http://entropia.de/">entropia</a> in december. I tried to touch many of the non-hardware-oriented topics in computer graphics, with a focus on those that are interesting (to me, at least) and easy to explain without too much background knowledge in math or computer science.</p>

<p>The talk was an experiment for me in several ways. First, the presentation style: The slides should contain as little text as possible, providing only visual assistance to what i said rather than guiding the talk themselves. In typical university or conference talks, i usually read the whole content-stuffed slide as soon as it appears without listening to what the lecturer says. The remaining two thirds of the time the slide takes usually consists of waiting for the next slide while trying not to fall asleep. I did not want to go as far into the opossite direction as Lawrence Lessig does because, obviously, the talk would be graphics-oriented and some of the pictures would need time to sink in and be explained. I think the style worked out fine and i surprised myself by talking quite a lot about slides with just one picture on them although i had not been practicing.</p>

<p>Second, the technical means: It was also the first time for me to use the <a href="http://latex-beamer.sourceforge.net/">Latex Beamer</a> Class for slides. Creating the slides was painless enough with the help of my <a href="http://erleuchtet.org/2008/11/latex-beamer-markup-less-sucka.html">latex preprocessor</a>, but the result did not convince me: (La)tex is not made for displaying pixel data on screen, causing images to be resized that want to displayed exactly 1:1. Most pdf viewers use Nearest Neighbour <a href="http://en.wikipedia.org/wiki/Interpolation">interpolation</a> for resizing pictures, making all my nice pictures look bad - which is somewhat embarrassing for a talk that covers image filtering and interpolation. With evince i found a pdf viewer that performs other interpolation methods, making the result bearable. Nevertheless i will have to find some other way to show images next time. Possibly i will create the slides as images themselves and present them with some image viewer like gqview. And maybe i&#8217;ll end up writing another minimalist slide-defining markup language that creates png images.</p>

<p>Third, i wanted to be able to publish the slides. This meant restricting myself to pictures released under some reasonably free licence or making my own. I ended up using many pictures from the <a href="http://commons.wikimedia.org">Wikimedia Commons</a>, usually modifying them to fit the black background. I also made many of the pictures myself. I included a file that provides proper attribution to the creators of the <a href="http://creativecommons.org/licenses/by/3.0/">CC-Attribution</a>-images in the <a href="http://entropia.de/wiki/Bild:Computer-graphics-part1.tar.gz">archive</a> containing the slides. This involved finding the authors of each of the images which was quite painful (and the reason for the long time it took to publish the slides). I&#8217;d really appreciate a Creative Commons license or something similar that does not force users of my work to remember or research my name - releasing into the Public Domain is not possible in Germany. Just granting all users every imaginable rights to to as they wish (which i hereby do) leaves me doubting the lawfulness of this statement. I&#8217;d really like some standard way of doing this.</p>

<p>All in all things went well and i certainly learned something in the two months it took to prepare a talk that was over in about 90 minutes. As i invested this considerable amount of time into something that did not last that long, i will certainly consider giving it again (or recycling the slides for a similar talk).</p>

<p>The talk&#8217;s <a href="http://entropia.de/wiki/Computergrafik_(Vortrag)"> article in the amazing entropia wiki</a> contains a link to the slides, some of whom may not make that much sense without any comment.</p>

<p>And here&#8217;s the flash version:</p>

<p><embed src="http://static.slideshare.net/swf/ssplayer2.swf?doc=computergraphicspart1-1231956273897879-2&amp;rel=0&amp;stripped_title=computer-graphics-part1-presentation" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></p>
]]>
        

    </content>
</entry>

<entry>
    <title>LaTeX beamer markup = less suckage</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2008/11/latex-beamer-markup-less-sucka.html" />
    <id>tag:erleuchtet.org,2008://3.24</id>

    <published>2008-11-11T23:18:05Z</published>
    <updated>2008-11-12T00:35:24Z</updated>

    <summary>There are many bad things about latex - like not being able to use footnotes in tables, color verbatim text for syntax highlighting or center math expressions. One general problem is its verbosity when only a small subset of its...</summary>
    <author>
        <name>cupe</name>
        
    </author>
    
        <category term="lisp" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="programming" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="talks" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[<p>There are many bad things about latex - like not being able to use footnotes in tables, color verbatim text for syntax highlighting or center math expressions. One general problem is its verbosity when only a small subset of its functionality is needed. Especially when using the beamer class, the mental and textual overhead made writing latex too bothersome for me to be fun. A simple wiki-style markup would suffice for most tasks when creating slides, with extra functionality only needed for special slides like titles. Wouldn't it be nice to write<br />
<em><br />
=Why tex needs to be replaced=<br />
There are countless reasons:<br />
* it's old<br />
* I don't like it</em></p>

<p>which would become<br />
<em><br />
\begin{frame}[plain]<br />
  \frametitle{Why tex needs to be replaced}<br />
There are countless reasons:<br />
\begin{itemize}<br />
  \item it's old<br />
  \item I don't like it<br />
\end{itemize}<br />
\end{frame}</em></p>

<p>I made a primitive LaTeX preprocessor in lisp that does just that. It handles slides, converts itemizations and includes and resizes graphics, while retaining all the nice features that make us use latex in the first place (i.e. the math mode). Things to improve include support for enumerations and flushright/centering and a more friendly shellscript. I will probably update it as I progress with the talk i'm currently preparing which will now be all the more awesome.</p>

<p>You can check out everything from svn://erleuchtet.org/texsucks or <span class="mt-enclosure mt-enclosure-file" style="display: inline;"><a href="http://erleuchtet.org/files/texsucks.tar.gz">download</a></span> it directly. With sbcl installed, just run make.sh to create an example pdf.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Project Overview: perfectstorm</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2008/03/project-overview-perfectstorm.html" />
    <id>tag:erleuchtet.org,2008://4.5</id>

    <published>2008-03-30T23:01:44Z</published>
    <updated>2008-04-02T17:18:12Z</updated>

    <summary> perfectstorm is a real time strategy game study written in common lisp using OpenGL for graphics display and cairo for texture generation. It is in active development with many of the basic features still unimplemented, but i decided the...</summary>
    <author>
        <name>cupe</name>
        
    </author>
    
        <category term="games" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="graphics" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="lisp" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/with-health-bars.png"><img alt="with-health-bars.png" src="http://erleuchtet.org/with-health-bars-thumb-300x225.png" width="300" height="225" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /></a></span></p>

<p><strong>perfectstorm</strong> is a real time strategy game study written in common lisp using OpenGL for graphics display and cairo for texture generation. It is in active development with many of the basic features still unimplemented, but i decided the effort put into it justifies some public documentation.</p>
]]>
        <![CDATA[<h2><strong>Why</strong></h2>

<p>I started perfectstorm because i was annoyed with the Artificial Intelligence offered in most commercial RTS games. Although significant academic research is going on, it seldom finds its way into released games due to publishers&#8217; wishes for absolute stability of the &#8220;gameplay experience&#8221; and the notion of AI as just being responsible for pathfinding plus something. Naturally, AI development can only begin late in the development cycle when the deadline is nearing. The most pressing feature the single &#8220;AI guy&#8221; most teams employ has to do is implementing pathfinding, which is not even part of AI if you want to see it that way. After that, only a poor makeshift enemy AI can be implemented before the product is shipped. Aside from that, writing good AI is hard. Or so i heard.</p>

<p>Most of the academic AI research going on seems to be tested on <a href="http://www.cs.ualberta.ca/~mburo/orts/">ORTS</a> , which seems to be decent and alive. Since i wanted to learn about general game coding and graphics development i decided not to use ORTS and write my own. And of course, i wanted to use lisp since i had not done a serious project with lisp and wanted to test its capability (and mine) to cope with heavy library interaction and larger real-world projects. The name &#8220;perfect storm&#8221; is a metaphor used to denote the interaction of several different parts to maximum overall effect, something i want both my RTS units and my code to perform :)</p>

<h2><strong>Details</strong></h2>

<p>For graphics, i first tested SDL, the 2D part of which turned out not to be hardware-acceleratable under X11. OpenGL was the only alternative and &#8212; thanks to the <a href="http://common-lisp.net/project/cl-opengl/">excellent cl-opengl bindings</a> &#8212; is very easy and fun to use. Now i needed textures and decided i wanted a <a href="http://www.everybody-dies.com/about/screenshots.html">defcon</a>-like slick minimalist-but-pleasing look. No complex models or realism was needed, so i figured drawing nice antialiased primitives and gradients would be enough and settled for <a href="http://cairographics.org">cairo</a>. While cairo is certainly not fast enough for drawing life animations, it produces very nice output and is reasonably easy to use, although the cl-cairo bindings are a pain (i hear that with cl-cairo2 and cl-cairo-cffi two alternatives have emerged).  After spending quite some time setting everything up and finally successfully extracting pixel data from cairo i started defining first units and implementing dummy game mechanics and graphics.</p>

<h2><strong>Status</strong></h2>

<p>Since then, the game has grown and, with the developer count rapidly soaring up to two, includes the following features:</p>

<ul>
<li>User-definable units and weapons that can be plugged together</li>
<li>Object-oriented very open design</li>
<li>Some 20 different textures, with the possibility to add more very easily</li>
<li>Fragment shaders for nice glows and flickering laser beams</li>
<li>Pathfinding</li>
<li>In-game developer console (aka REPL)</li>
</ul>

<h2><strong>Future Plans</strong></h2>

<p>In the near future, i&#8217;d like to see the following things:</p>

<ul>
<li>Steering behaviours for units (currently work in progress)</li>
<li>A first easily replaceable resource scheme</li>
<li>Buildings</li>
<li>More verbose GUI</li>
<li>Dummy ai for first playtesting</li>
</ul>

<p>You are welcome to try it and play around if you like, or even contribute something.</p>

<p>Currently, the svn version is not guaranteed to be in any usable state or even to compile. Since we are more or less concentrating on one feature at the time, it is likely you will see some debug output concering the current development focus when just starting it. Dependencies are listed in the README file. You can check it out from svn://erleuchtet.org/perfectstorm. You will need both the cairo and OpenGL bindings from the same svn repo since i added some features that are needed by perfectstorm.</p>

<p><strong>But beware!</strong> the current state is not that presentable: you&#8217;ll just see pathfinding debug output at the moment. When a first dummy is playable and the code is cleaned up a bit we&#8217;ll make a project page.</p>

<h2><strong>Screenshots</strong></h2>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/pathfinding.png"><img alt="pathfinding.png" src="http://erleuchtet.org/pathfinding-thumb-300x234.png" width="300" height="234" class="mt-image-none" style="" /></a></span></p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/land_vs_air.png"><img alt="land_vs_air.png" src="http://erleuchtet.org/land_vs_air-thumb-300x225.png" width="300" height="225" class="mt-image-none" style="" /></a></span></p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/shader-on.png"><img alt="shader-on.png" src="http://erleuchtet.org/shader-on-thumb-300x225.png" width="300" height="225" class="mt-image-none" style="" /></a></span></p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/shader-off.png"><img alt="shader-off.png" src="http://erleuchtet.org/shader-off-thumb-300x225.png" width="300" height="225" class="mt-image-none" style="" /></a></span></p>
]]>
    </content>
</entry>

<entry>
    <title>Terrain Generation 90ies-style</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2008/03/terrain-generation-90iesstyle.html" />
    <id>tag:erleuchtet.org,2008://4.4</id>

    <published>2008-03-20T15:02:06Z</published>
    <updated>2008-03-20T21:30:00Z</updated>

    <summary>If you have played with Bryce or Terragen you know that Terrain Generation is fun and useless. The Midpoint Displacement Algorithm is one of the simplest methods to build a triangle mesh that resembles the terrain found in nature. You...</summary>
    <author>
        <name>cupe</name>
        
    </author>
    
        <category term="graphics" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="lisp" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[<p>If you have played with Bryce or Terragen you know that Terrain Generation is fun and useless. The Midpoint Displacement Algorithm is one of the simplest methods to build a triangle mesh that resembles the terrain found in nature. You can see its output on the right.
<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/displacement.jpg"><img alt="displacement.jpg" src="http://erleuchtet.org/displacement-thumb-200x149.jpg" width="200" height="149" class="mt-image-right" style="" /></a></span></p>

<p>While this looks like a mountain of some sorts, the algorithm does not produce good mountains every time you invoke it. Instead, the result is quite random and almost always bad. Have a look at the algorithm:</p>

<blockquote>
  <ol>
  <li>Make one triangle.</li>
  <li>Subdivide all your triangles into four new ones (use the edge midpoints as new vertices).</li>
  <li>Move your new midpoints along the y-axis by a random offset.</li>
  <li>Repeat 2 and 3 with half the offset.</li>
  </ol>
</blockquote>

<p>The algorithm refines its terrain model recursively with every step, producing self-similar (in other words fractal) patches of terrain. It is short and easy to understand. Too bad real mountains are only superficially self-similar. One of the most visible shortcomings of the algorithm can be seen when the random displacement is replaced by its expected value. The &#8220;expected value&#8221; for the algorithm looks like this:</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/displacement-norandom.jpg"><img alt="displacement-norandom.jpg" src="http://erleuchtet.org/displacement-norandom-thumb-200x149.jpg" width="200" height="149" class="mt-image-left" style="" /></a></span></p>

<p>These furrows can be seen in most randomly displaced terrains, too, when viewed from specific angles or directly from above. (The yellow cube is the light source)</p>

<p>A better approach might be to use <a href="http://en.wikipedia.org/wiki/Perlin_noise">Perlin noise</a> as a heightmap since it does not introduce visible artifacts. I&#8217;ll probably test this later.</p>

<p>Concerning the implementation, i spent most of the time implementing the fundamental mesh operations like splitting lines and triangles. Since this will not be last time i&#8217;ll handle triangle meshes and i might save other Lispers the pain i am thinking about expanding this and publishing it as a general mesh handling and drawing library for Common Lisp.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>a quick guide to shaders</title>
    <link rel="alternate" type="text/html" href="http://erleuchtet.org/2008/03/a-quick-guide-to-shaders.html" />
    <id>tag:erleuchtet.org,2008://3.5</id>

    <published>2008-03-14T00:09:35Z</published>
    <updated>2009-01-15T02:29:42Z</updated>

    <summary>A shader is a small program that is executed on the graphics card. On modern graphics cards, up to 128 shader programs can be executed in parallel. Conventional parallel programming is hard because there are resources to be shared, but...</summary>
    <author>
        <name>cupe</name>
        
    </author>
    
        <category term="graphics" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://erleuchtet.org/">
        <![CDATA[<p>A shader is a small program that is executed on the graphics card. On modern graphics cards, up to 128 shader programs can be executed in parallel. Conventional parallel programming is hard because there are resources to be shared, but shader programs are completely independent, allowing the graphics card manufacturers to add more shader pipelines at will. Currently there are two important types of shaders: vertex shaders and fragment shaders. For each frame that is rendered, all visible vertices (read: nodes of the mesh) are processed by vertex shaders which can modify their position or attributes like normals, color or any other user-defined attributes.</p>

<p><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://erleuchtet.org/fraktale_teekanne.png"><img alt="fraktale_teekanne.png" src="http://erleuchtet.org/fraktale_teekanne-thumb-200x150.png" width="200" height="150" class="mt-image-left" style="float: left; margin: 0 20px 20px 0;" /></a></span>
One fragment corresponds to one pixel on the screen. For each fragment, the fragment shader is called. A fragment belongs to the polygon visible at the position of the corresponding pixel on the screen, i.e. the intersection of the pixel ray with the polygon defines the fragment&#8217;s position in the 3d world. The fragment shader thus knows its position within the polygon and can use this information, e.g. for looking up (and returning) the color of the polygon&#8217;s texture at that place. When using fragment shaders, OpenGL will not do texture mapping, you will have to use a trivial fragment shader to accomplish what would happen automatically without shaders.</p>

<p>Information can pass from the vertex shader to the fragment shader, but not in the other direction. The shader programmer may define arbitrary &#8220;varying&#8221; constants which can be written by the vertex shader and are, linearly interpolated between the vertices, available to the fragment shader. For each triangle three vertex shader executions need to be made, but a much larger amount of fragment shader executions is needed, depending on the size of the triangle on the screen.</p>

<p>Naturally, the fragment shader has access to all of the triangle&#8217;s textures. For advanced shaders, like those in modern games, these auxiliary textures usually contain a normal map and/or a height map, i.e. the direction of the normal for each texel (the three coordinates of the normal are stored as rgb) or the height of the texel compared to the triangle plane (as a grey value) is available. With this information a fragment shader can do arbitrarily complex stuff, ranging from good old bump mapping to a wide variety of occlusion and parallax mapping techniques, the use of gloss maps or the design of weird materials, their colors changing with the angle the camera looks at them.</p>

<p>Since it is also possible to pass values (e.g. a tick count or wind speed) from OpenGL to the shaders, they are used to implement flags fluttering in the wind, rocket engines causing ripples in the air or other animations or effects you would have thought the CPU knew about.</p>

<p>In my experiments i used GLSL (the OpenGL Shader Language), a c-like mid-level language that is compiled into assembly code that can be executed on the graphics hardware. GLSL provides clipping, matrix multiplication, dot product, etc. as primitive operations, along with some useful predefined special variables that are always present and need not be declared.</p>

<p>In the quest for more and more parallelization in computing, shaders may be the most successful example since shader parallelization itself demands no intervention by the programmer at all. Shaders are bound to become even more complex: with geometry shaders (available on graphics cards labeled &#8220;Shader Level 4&#8221; or &#8220;DirectX 10&#8221;, something my setup lacks) it becomes possible to generate geometry on the fly and even run particle systems entirely on the GLPU. It can be expected that even more parallelizable work will be taken from the CPU and put onto the GPU, providing an infinite playground for the demo coder. Graphics programming has never been this easy and fun. 500 GFLOPS are just <strike>$400</strike> $200 away :)</p>

<p>If you are interested, have a look at <a href="http://www.typhoonlabs.com/">typhoon labs</a>&#8217; hard-to-find ex-website, hosting Shader Designer, the tool used in the screenshot above as well as a very nice GLSL tutorial with shiny pictures.</p>
]]>
        

    </content>
</entry>

</feed>

