<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5451790455362512006</id><updated>2012-03-15T13:32:01.974+01:00</updated><category term='jQuery'/><category term='GulaschProgrammierNacht'/><category term='shader'/><category term='GameLab Karlsruhe'/><category term='libfirm'/><category term='video game'/><category term='Devmania'/><category term='Unity3D'/><category term='Java'/><category term='Löve2D'/><category term='D'/><category term='CouchDB'/><category term='C++'/><category term='Global Game Jam'/><category term='internationalization'/><category term='SCons'/><category term='Experimental Gameplay Project'/><category term='compilation'/><category term='Box2D'/><category term='SFML'/><category term='Lua'/><category term='OpenBOR'/><category term='JavaScript'/><category term='CouchApp'/><category term='GLFW'/><category term='prototype'/><category term='OpenGL'/><category term='HTML5'/><title type='text'>Jo's kitchen</title><subtitle type='html'>Agile engineering, lean development and delicious cakes.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-3677671933337800758</id><published>2012-03-15T04:42:00.000+01:00</published><updated>2012-03-15T13:32:01.984+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='shader'/><category scheme='http://www.blogger.com/atom/ns#' term='GLFW'/><category scheme='http://www.blogger.com/atom/ns#' term='D'/><category scheme='http://www.blogger.com/atom/ns#' term='SCons'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Blur effect</title><content type='html'>&lt;br /&gt;What I said in &lt;a href="http://bloutiouf.blogspot.com/2011/08/introducing-shaders-in-d.html"&gt;my previous post about shaders in D&lt;/a&gt; is sadly not up-to-date, so I want to bring something new. Here is a little project testing&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://github.com/aldacron/Derelict3" target="_blank"&gt;Derelict3&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.opengl.org/registry/" target="_blank"&gt;OpenGL 3+ API&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Multipass post-processing effect via shaders and render-to-texture&lt;/li&gt;&lt;li&gt;D builder for SCons&lt;/li&gt;&lt;li&gt;SCons targets&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Eventually, it results as a program blurring a restricted zone of an image.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;span style="margin-left: auto; margin-right: auto;"&gt;&lt;a href="https://github.com/Bloutiouf/blur-effect" target="_blank"&gt;&lt;img border="0" height="320" src="http://1.bp.blogspot.com/-KNWf5SR2xVE/T2E8cZF2BsI/AAAAAAAADwc/lfvCYeZCWTQ/s320/blur.jpg" width="307" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Blurred cow on a sharp photo.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;strong&gt;&lt;a href="https://github.com/Bloutiouf/blur-effect" target="_blank"&gt;Get the project on GitHub.&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Environment:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;install &lt;a href="http://www.cmake.org/" target="_blank"&gt;CMake&lt;/a&gt;&lt;/li&gt;&lt;li&gt;clone and compile GLFW using CMake:&amp;nbsp;&lt;a href="git://glfw.git.sourceforge.net/gitroot/glfw/glfw"&gt;git://glfw.git.sourceforge.net/gitroot/glfw/glfw&lt;/a&gt;&lt;/li&gt;&lt;li&gt;obtain DevIL's libraries (packages exists):&amp;nbsp;&lt;a href="http://openil.sourceforge.net/download.php"&gt;http://openil.sourceforge.net/download.php&lt;/a&gt;&lt;/li&gt;&lt;li&gt;install a D2 compiler:&amp;nbsp;&lt;a href="http://dlang.org/dmd-windows.html"&gt;http://dlang.org/dmd-windows.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;clone Derelict3:&amp;nbsp;&lt;a href="https://github.com/aldacron/Derelict3.git"&gt;https://github.com/aldacron/Derelict3.git&lt;/a&gt;&lt;/li&gt;&lt;li&gt;configure your D2 compiler to append the path to Derelict3 (in &lt;i&gt;sc.ini&lt;/i&gt; with DMD2)&lt;/li&gt;&lt;li&gt;install &lt;a href="http://www.python.org/download/" target="_blank"&gt;Python 2.7&lt;/a&gt; and &lt;a href="http://www.scons.org/download.php" target="_blank"&gt;SCons&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Derelict3&lt;/h2&gt;&lt;a href="https://github.com/aldacron/Derelict3" target="_blank"&gt;Derelict3&lt;/a&gt; is the new version of Derelict, a project providing wrappers in D for C libraries. It is though an alpha version, so consider using Derelict2 if you really want to pacify your boss.&lt;br /&gt;&lt;br /&gt;The hearth of this project is DerelictGL3, which wraps OpenGL up to the latest version 4.2. I'll take about OpenGL in the next section.&lt;br /&gt;&lt;br /&gt;In order to use OpenGL, we have to create a window and its OpenGL context. Derelict3 provides two libraries: SDL2 or GLFW3. Both are new versions in development, so once again, the code may break up at any moment. As I used DerelictSDL last time, I tried to stay on this library. That was a bad idea: SDL2 is not able to open a OpenGL 3.2+ context for now. So I give DerelictGLFW3 a try. This time it works up to OpenGL 3.3, my graphics card doesn't seem to accept any higher version. Both libraries have somewhat similar concepts, so it was not a big deal.&lt;br /&gt;&lt;br /&gt;I finally used DerelictIL, a wrapper of the image library&amp;nbsp;&lt;a href="http://openil.sourceforge.net/" target="_blank"&gt;DevIL&lt;/a&gt;, to load a picture as OpenGL texture. Loading is then really easy, it only consists of a function call. Again, this may not fit to production environments, as the textures should be compressed on some low-level format which are much more efficient. But for test purposes, it comes in handy.&lt;br /&gt;&lt;br /&gt;The wrapper code is very lightweight, it's easy to dig into files to find functions' prototype or constants. It also seems easy to make a wrapper over any library, next time I'll try that. However I regret that the files contain no documentation, and even no name for the function parameters. As they wrap libraries in development, prototypes may change compared with the libraries' official documentation. Then don't be surprise if it doesn't match.&lt;br /&gt;&lt;h2&gt;OpenGL 3+&lt;/h2&gt;I was playing with OpenGL at a time where shaders didn't exist. As new versions come, the API changes, sometimes radically. As such, glBegin and glEnd are now deprecated, view and projection matrices are now handled by shaders... well, let's learn the modern OpenGL from scratch.&amp;nbsp;Sadly, a lot of resources on Internet still use old methods, or a mix of old an new ones...&lt;br /&gt;&lt;br /&gt;I don't plan to deliver for the mass market, so I target version 3.3 (but I'll understand if you target a lower version). Shaders have also to declare GLSL version 330.&lt;br /&gt;&lt;br /&gt;My goal was only to blur parts of an image, but this can be extended to simulate depth of field for example. This is entirely a post-processing effects, so it involves shaders. The basic idea for the effect is to get a blurry version of the image, and to mix it with the original, sharp version, with a blending factor depending on the position of the pixels (in my case, it is related to the mouse cursor position). This is obtained in one pass, but getting a blurry photo itself involves two passes (&lt;a href="http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/" target="_blank"&gt;explanations&lt;/a&gt;), so we end up with three passes: horizontal blur, vertical blur, and mix.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" height="81" src="http://4.bp.blogspot.com/-lH0FRr1ymU8/T2Fke3IvANI/AAAAAAAADxA/37MYWFjB5D8/s320/blur-passes.png" width="320" /&gt;&lt;/div&gt;&lt;br /&gt;When involving several passes, the output of a pass shall be the input of the next pass, except for the last pass which can render directly on the screen. This is known as Render to Texture (RTT for short), indeed the output of a pass is written to a texture, which in turn will feed the next pass. RTT requires a framebuffer defining the output textures. In this case, there is only a single output, the color of each pixel, but one may also define the depth buffer or render on several textures. I don't want to explain further, &lt;a href="https://www.google.de/search?q=opengl+render+to+texture" target="_blank"&gt;a lot of tutorials already exist&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Feeding a pass with a texture&amp;nbsp;eventually&amp;nbsp;means simply apply the texture on a quad covering the whole screen space. I used to draw quad with four vertices, but a friend told me a simple triangle large enough could cover the screen as well, even being better for the graphical pipeline (not verified). To render faces using the new API, we need to set a vertex buffer object, an UV buffer object and an index buffer object. On top of that, a vertex array object retains the states, so it will be easier to restore them in the rendering loop. Again, I don't explain in detail, &lt;a href="https://www.google.de/search?q=opengl+vertex+buffer+object" target="_blank"&gt;lots of sites already do&lt;/a&gt;. The loop is really straightforward: bind a framebuffer, the correct texture, and a shader program, render the quad and voila the texture contains data for the next pass.&lt;br /&gt;&lt;br /&gt;Shaders are not complicated. Vertex shaders don't do anything related to the post-processing effect in itself, everything is in the fragment shaders. Below is the code for the horizontal blur, inspired from &lt;a href="http://www.gamerendering.com/2008/10/11/gaussian-blur-filter-shader/" target="_blank"&gt;an article on GameRendering.com&lt;/a&gt;. The shaders in that article have a little flaw: the sum of all coefficients is 0.98, resulting in a small but noticeable darkening. The following code fixes this problem by adding two new samples with coefficient 0.01.&lt;br /&gt;&lt;pre class="code"&gt;#version 330&lt;br /&gt;&lt;br /&gt;in vec2 texCoord;&lt;br /&gt;&lt;br /&gt;out vec4 fragColor;&lt;br /&gt;&lt;br /&gt;uniform sampler2D texture;&lt;br /&gt;uniform vec2 resolution;&lt;br /&gt;&lt;br /&gt;void main() {&lt;br /&gt;    float blurSize = 1.0 / resolution.x;&lt;br /&gt;    &lt;br /&gt;    vec4 sum = vec4(0.0);&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x - 5.0 * blurSize, texCoord.y)) * 0.01;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x - 4.0 * blurSize, texCoord.y)) * 0.05;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x - 3.0 * blurSize, texCoord.y)) * 0.09;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x - 2.0 * blurSize, texCoord.y)) * 0.12;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x -       blurSize, texCoord.y)) * 0.15;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x                 , texCoord.y)) * 0.16;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x +       blurSize, texCoord.y)) * 0.15;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x + 2.0 * blurSize, texCoord.y)) * 0.12;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x + 3.0 * blurSize, texCoord.y)) * 0.09;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x + 4.0 * blurSize, texCoord.y)) * 0.05;&lt;br /&gt;    sum += texture2D(texture, vec2(texCoord.x + 5.0 * blurSize, texCoord.y)) * 0.01;&lt;br /&gt;    &lt;br /&gt;    fragColor = sum;&lt;br /&gt;}&lt;/pre&gt;As I write, I remark that blurSize is constant for all fragments so that I could have made the calculation in the vertex shader. Anyway it's not very optimized.&lt;br /&gt;&lt;h2&gt;SCons&lt;/h2&gt;I used DSSS last time. This project hasn't been updated for years, still compiles using D1 (discontinued by end 2012)... so let's try something else. As I use SCons for my C++ projects, I've though it would be great to use the same system. Luckily, it has built-in support for D!&lt;br /&gt;&lt;br /&gt;Building a D program is the same as for a C++ program:&lt;br /&gt;&lt;pre class="code"&gt;env.Program('bin/program', Glob('src/*.d'))&lt;/pre&gt;Really easy. The compilation flags for DMD are however quite different than GCC, pay attention.&lt;br /&gt;&lt;br /&gt;Another thing I never did is to specify targets, that is, being able to run 'scons release' or 'scons debug'. This is well-handled with Alias, the trick is to retrieve the return value of Program or any other builder. I've separated each target in its own SConscript, partly because of the VariantDir. To pass a value through a SConscript, use Return. Besides, 'scons .' builds everything, so 'all' is a simple alias to '.'.&lt;br /&gt;&lt;pre class="code"&gt;debug = SConscript('SConscript.debug', variant_dir='build/debug', duplicate=0)&lt;br /&gt;release = SConscript('SConscript.release', variant_dir='build/release', duplicate=0)&lt;br /&gt;&lt;br /&gt;Alias('all', '.')&lt;br /&gt;Alias('debug', debug)&lt;br /&gt;Alias('release', release)&lt;br /&gt;Default(debug)&lt;/pre&gt;&lt;br /&gt;That's all for this project!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-3677671933337800758?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/3677671933337800758/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2012/03/blur-effect.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/3677671933337800758'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/3677671933337800758'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2012/03/blur-effect.html' title='Blur effect'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-KNWf5SR2xVE/T2E8cZF2BsI/AAAAAAAADwc/lfvCYeZCWTQ/s72-c/blur.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-7577401069376077353</id><published>2012-01-31T14:41:00.000+01:00</published><updated>2012-02-06T03:35:26.750+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Unity3D'/><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='HTML5'/><category scheme='http://www.blogger.com/atom/ns#' term='Global Game Jam'/><category scheme='http://www.blogger.com/atom/ns#' term='compilation'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>Veggie Might</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-xdLPdIJ4PqQ/TyfaDNwHdsI/AAAAAAAADrI/q89C5LLHRls/s1600/knight.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://4.bp.blogspot.com/-xdLPdIJ4PqQ/TyfaDNwHdsI/AAAAAAAADrI/q89C5LLHRls/s200/knight.png" width="144" /&gt;&lt;/a&gt;&lt;/div&gt;As I announced last week, I participed once again in the &lt;a href="http://globalgamejam.org/" target="_blank"&gt;Global Game Jam&lt;/a&gt;. Sadly, our game was not ready at the end of the 48 hours, but there are still some lessons to draw. Moreover, we are planning to continue its development, so version 2 would be presentable.&lt;br /&gt;&lt;br /&gt;The game is entitled Veggie Might. This is a MMO game where armies of Baron Broccoli and Count Carrots fight for... well, nothing at this time, but we've thought to bases to take over in a Domination mode. Anyway, we wanted to represent a huge, endless battle a la Lord of the Rings, and this is the link with this year's theme &lt;a href="http://en.wikipedia.org/wiki/Ouroboros" target="_blank"&gt;Ouroboros&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We used HTML5 and WebSockets. The idea is to let the players enter the battle as soon as possible. As such, we don't wanted them to download and install the game, it would have been an extreme barrier to the player amount. Therefore with HTML5, they just have to visit a web page and they're ready to go. Moreover, the other programmer and I were pretty new to this world of real-time online games, so we were willing to cross the gap.&lt;br /&gt;&lt;br /&gt;The server was programmed in Java. I wanted rather to use Node.js to iterate faster, but I was angry whether it would support the overhead of 1024 players. Maybe it wasn't the proper question at the time, but anyway, it worked. The server is basically in charge of relaying one player's messages to the others (we didn't bother that much with security).&lt;br /&gt;&lt;br /&gt;Server and clients communicate via WebSockets, on the server we used&amp;nbsp;&lt;a href="https://github.com/TooTallNate/Java-WebSocket" target="_blank"&gt;TooTallNate's WebSocket library&lt;/a&gt;. It works as expected, that is, the user sends and receives messages like with any other network library. Our messages were JSON encoded, there is no need to design a binary protocol in a prototyping phase.&lt;br /&gt;&lt;br /&gt;The client uses &lt;a href="http://www.limejs.com/" target="_blank"&gt;LimeJS&lt;/a&gt;, a framework handling graphical scenes, events and sounds. The scene is a tree of nodes, Sprites being a particular node type. This translates well into HTML where the scene is a tree of DIV, and is very similar to Flash programming.&lt;br /&gt;&lt;br /&gt;LimeJS is actually a library to use with &lt;a href="http://code.google.com/closure/" target="_blank"&gt;Closure&lt;/a&gt;. Basically it is a&amp;nbsp;JavaScript&amp;nbsp;to&amp;nbsp;JavaScript&amp;nbsp;compiler, and that reminds me my work on libfirm (and that I also have to continue this work...). It adds a system for including other files that JavaScript misses a lot.&lt;br /&gt;&lt;br /&gt;I wanted to do the client side to see the problems related to prediction and collisions. I've already done a project handling these problems, but wasn't in charge of that part. I guess it's useless to tell right now how I've done it as it's not working properly. One thing to note, however: I worked with a mockup server, actually a false WebSocket interface which simulates a server. This was very practical since I didn't have to wait the features on the server to be ready before making my own code. Therefore I'll always recommend to work with mockups on projects related to network.&lt;br /&gt;&lt;br /&gt;The artist worked with an incredible interactive pen display. He drew in Flash, allowing to quickly see animations. The exported SWF sequence was transformed into a PNG sprite sheet with &lt;a href="http://www.bit-101.com/blog/?p=2977" target="_blank"&gt;SWFSheet&lt;/a&gt;. The anchor point was buggy and I had to handle it outside of the animation controller.&lt;br /&gt;&lt;br /&gt;I recommend two games from my location: &lt;a href="http://globalgamejam.org/2012/quadd" target="_blank"&gt;Quadd&lt;/a&gt; for the hardcore gamers, and &lt;a href="http://globalgamejam.org/2012/backdraft" target="_blank"&gt;Backdraft&lt;/a&gt; for the softer ones. Both of them were made with Unity3D. A programmer on Backdraft told me that Unity3D was hard to use for a pure 2D game. Special ovation for the group from Toulouse which &lt;a href="https://picasaweb.google.com/lh/photo/_lC_gpwRViFohMmiZq-Z-dMTjNZETYmyPJy0liipFm0?feat=embedwebsite" target="_blank"&gt;has spent the whole event doing paper prototyping&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;A last word about the event: you, as a creator (programmer as well as artist), really have to attend to this kind of events. You'll learn a lot. And don't try to stay awake, particularly at the beginning. By sleeping, the brain will continue to work on your ideas, and this is much more efficient.&lt;br /&gt;&lt;br /&gt;As I said, we are willing to continue the development, so stay tuned!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-7577401069376077353?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/7577401069376077353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2012/01/veggie-might.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/7577401069376077353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/7577401069376077353'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2012/01/veggie-might.html' title='Veggie Might'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-xdLPdIJ4PqQ/TyfaDNwHdsI/AAAAAAAADrI/q89C5LLHRls/s72-c/knight.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-2186748676365102160</id><published>2012-01-26T05:08:00.000+01:00</published><updated>2012-01-26T11:37:08.246+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><category scheme='http://www.blogger.com/atom/ns#' term='Experimental Gameplay Project'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='Löve2D'/><category scheme='http://www.blogger.com/atom/ns#' term='Box2D'/><title type='text'>Bunt</title><content type='html'>&lt;a href="http://1.bp.blogspot.com/-lqT06iNRf_U/TyC4vWYeJfI/AAAAAAAADYM/SyU0YKB0RIw/s1600/star.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-lqT06iNRf_U/TyC4vWYeJfI/AAAAAAAADYM/SyU0YKB0RIw/s1600/star.png" /&gt;&lt;/a&gt;I had to participate in the current &lt;a href="http://experimentalgameplay.com/" target="_blank"&gt;Experimental Gameplay Project&lt;/a&gt;'s competition: some games will be shown at the &lt;a href="http://www.stattbad.net/" target="_blank"&gt;Stattbad Gallery&lt;/a&gt; in Berlin! Bunt is my prototype in response to the theme &lt;a href="http://experimentalgameplay.com/blog/2011/12/5-buttons-competition-in-decemberjanuary/" target="_blank"&gt;Five buttons&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Windows users: &lt;a href="http://gamejolt.com/open-source/games/other/bunt/7015/" target="_blank"&gt;&lt;b&gt;play this game&lt;/b&gt;&lt;/a&gt; with no installation! (&lt;i&gt;quick play&lt;/i&gt;)&lt;br /&gt;Mac and Linux users: huh, you still need to install &lt;a href="https://love2d.org/" target="_blank"&gt;Löve2D&lt;/a&gt; and &lt;a href="http://gamejolt.com/open-source/games/bunt/files/love-version/download/7015/9004/" target="_blank"&gt;play this version&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Bunt means multicolored in German. Indeed the game is all about interactivity with colored objects. In addition, bunt is four letters long, and the game uses four primary colors. Each key from 1 to 4 is assigned a color. By pressing a key, the player interacts with objects of the corresponding color. The goal is to touch every star in the level to go to the next one.&lt;br /&gt;&lt;br /&gt;What are those interactions? Something simple, easy to understand, funny to use, and ultimately allowing to solve crazy puzzles. It was important that each object has a different interaction, otherwise it would be like "eh look, something new! But actually you already know it." During playtests for a previous unreleased prototype, we've seen that players enjoy discovering new elements of gameplay. This is an extreme illustration of this concept.&lt;br /&gt;&lt;br /&gt;I started the competition with the intention to develop a puzzle game where rhythm helps to solve the levels. The base would be little pixels a la 8bit depicting sound frequencies. Keys would allow to interact with these pixels, to move them in different directions. But then I thought it would be very limited. So, let's add more things to interact with. Hey it's cool! Let's go further, all the buttons do the same interaction. And eventually I dropped the 8bit stuff for a colored design. So, quite different from my first thoughts.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-suLNgJ3OskE/TyC7OlVqgRI/AAAAAAAADYU/hRvkoL_PPpg/s1600/BUNT_2012-01-26_03-29-28.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="250" src="http://1.bp.blogspot.com/-suLNgJ3OskE/TyC7OlVqgRI/AAAAAAAADYU/hRvkoL_PPpg/s400/BUNT_2012-01-26_03-29-28.png" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Press blue or yellow and the crate will fall.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Levels present a simple situation. The player should immediately understand what to do to reach the stars. For instance, the second level contained&amp;nbsp;just the frog&amp;nbsp;at the beginning. Two friends tested the game and were stuck here. At the second level?! Damn, was it not so obvious that a frog can jump in rhythm? No it wasn't. So I added a little trampoline, and it became evident that the frog could jump with impetus (it was also more logical, a frog can't gain impetus just by itself). Levels are also designed to be short. Well, the last ones may require some experience, but the first ones are very short, and this creates a little addiction to the game in the same way that &lt;a href="http://www.wariowarediy.com/" target="_blank"&gt;WarioWares&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Level design actually starts before the first level. The first thing the player sees is the menu. "Play the game with these keys", each key has a color, there are colored balloons... let's press 2. Oh, the balloon blows up! This is the very first understanding of the gameplay: pressing a key will blow up balloons of the corresponding color. The first level comforts this idea, and introduces the star (it may not be sure what the star actually does, but the next levels will ensure that they have to be touched by something). The second level has a frog instead, and introduces the notion of pressing keys several times on precise moments. The third one uses another color, showing that the principle are the same for all keys, and needs the player to press the key for a finite duration. And so on... almost each level adds some element to the game.&lt;br /&gt;&lt;br /&gt;The player should quickly understand that he can restart the level when he can't reach the stars anymore, but that this is no punishment. At first, I made a in-game menu, appearing when the player presses 5. Then, the key 2 allowed to restart the level. A friend told me it was too long and besides the menu was useless.&amp;nbsp;True. So let's just press 5 to restart, and press longer to quit.&lt;br /&gt;&lt;br /&gt;Colors were chosen mainly to change between levels. In addition, there is a physical constraint: the game is meant to be played with five big grounded plots, and players can't press both on 1 and 4 at the same time. Therefore keys are often used in pairs. Moreover, the most difficult levels use keys on the right, because the Restart key is closer.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-IgOpiVDDliQ/TyC8YDd0_vI/AAAAAAAADYc/xyA4TJp8LeA/s1600/BUNT_2012-01-26_03-26-51.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="250" src="http://2.bp.blogspot.com/-IgOpiVDDliQ/TyC8YDd0_vI/AAAAAAAADYc/xyA4TJp8LeA/s400/BUNT_2012-01-26_03-26-51.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Once again, I've&amp;nbsp;developed&amp;nbsp;this prototype with &lt;a href="https://love2d.org/" target="_blank"&gt;Löve2D&lt;/a&gt;. As this game heavily relies on physics, I've used &lt;a href="http://box2d.org/" target="_blank"&gt;Box2D&lt;/a&gt; (included in Löve2D). I've understood why &lt;a href="http://bloutiouf.blogspot.com/2011/06/magnetic-glues.html" target="_blank"&gt;Magnetic glues&lt;/a&gt; sometimes bugs (I won't fix it anyway). The reason is well documented:&amp;nbsp;"Using &lt;a href="https://love2d.org/wiki/Shape:destroy" target="_blank"&gt;Shape:destroy&lt;/a&gt; when there is an active remove callback can lead to a crash. It is possible to &lt;a href="https://love2d.org/wiki/Remove_Workaround" target="_blank"&gt;work around&lt;/a&gt; this issue by only destroying object that are not in active contact with anything." but I haven't clearly understood what it means. Simply do not delete any shape which is in contact. The solution I've chosen is to remove entities by moving them outside the screen and to save them in a separate list until they are no contact with them (therefore I increment a variable in the add callback and decrement it in the remove callback).&lt;br /&gt;&lt;br /&gt;Entities are just containers for a set of components. Almost all objects have a body component (physics) and a sprite component,&amp;nbsp;furthermore&amp;nbsp;the interactive objects have a logic component which basically allows for custom scripts related to interaction. But... I feel like it misses something. On Magnetic glues I've separated the concepts of behavior and game object, but I've added a huge overload with a signal-slot system... Needless to say, I've sometimes hacked the game engine (aka break the encapsulation) to keep things simpler. The last level with the puzzle is a hack of&amp;nbsp;both&amp;nbsp;the game engine and game principles, but I've thought I need to break the game before the end, to calm down the player.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-n06QDjjd99I/TyC8rbgBVgI/AAAAAAAADYk/OUospBVxLT8/s1600/BUNT_2012-01-26_03-27-44.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="250" src="http://1.bp.blogspot.com/-n06QDjjd99I/TyC8rbgBVgI/AAAAAAAADYk/OUospBVxLT8/s400/BUNT_2012-01-26_03-27-44.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The graphics were made with &lt;a href="http://inkscape.org/" target="_blank"&gt;Inkscape&lt;/a&gt;. The background was inspired from &lt;a href="http://www.eurodroid.com/pics/angry-birds-easter.jpg" target="_blank"&gt;Angry Birds&lt;/a&gt;. The green, open landscape adds nothing to the level itself, yet it subconsciously relieves the player. For me too, because finding and designing objects for mostly two uses is exhausting... The little GFX and SFX clues were very easy to add, yet it makes the game more attractive. Although I'm still not proud of the sound design and I'll work on that on the future prototypes.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;a href="http://upload.wikimedia.org/wikipedia/commons/6/67/Frets_on_fire_man.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://upload.wikimedia.org/wikipedia/commons/6/67/Frets_on_fire_man.png" width="100" /&gt;&lt;/a&gt;&lt;/div&gt;As a last anecdote, there are two alternative control schemes. The first is to use keys from F1 to F5, because I've wanted to play the game like a guitarist in &lt;a href="http://fretsonfire.sourceforge.net/" target="_blank"&gt;Frets on Fire&lt;/a&gt;. It also seems that Löve doesn't support the keys 1 to 5 very well under Linux, but I currently can't verify. The second input method is to use a Xbox controller, as it uses the same colors for its buttons. Any other button restarts the level. By the way, the order of colors (blue, green, yellow, red) was chosen because of the button disposition on the controller and the &lt;a href="http://www.ddrgame.com/" target="_blank"&gt;Dance Dance Revolution&lt;/a&gt; transfer function.&lt;br /&gt;&lt;br /&gt;Don't forget: &lt;a href="http://globalgamejam.org/" target="_blank"&gt;Global Game Jam&lt;/a&gt;&amp;nbsp;next week-end!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-2186748676365102160?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/2186748676365102160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2012/01/bunt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/2186748676365102160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/2186748676365102160'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2012/01/bunt.html' title='Bunt'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-lqT06iNRf_U/TyC4vWYeJfI/AAAAAAAADYM/SyU0YKB0RIw/s72-c/star.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-3625942516601656949</id><published>2011-12-23T01:26:00.000+01:00</published><updated>2012-01-09T01:02:40.786+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GameLab Karlsruhe'/><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenBOR'/><title type='text'>Revenge of the Christmas tree</title><content type='html'>&lt;a href="https://picasaweb.google.com/lh/photo/K9gDj7-lrHHRAPR5Fy7r7dMTjNZETYmyPJy0liipFm0?feat=embedwebsite" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img height="108" src="https://lh5.googleusercontent.com/-PaKOk1FPdpI/Tuvn7wf2NZI/AAAAAAAADWA/LfkrH_uHKDk/s144/revenge_start.png" width="144" /&gt;&lt;/a&gt;With some people of the &lt;a href="http://postdigital.hfg-karlsruhe.de/gamelab" target="_blank"&gt;GameLab Karlsruhe&lt;/a&gt;, we made the game Revenge of the Christmas tree for the exhibition&amp;nbsp;&lt;a href="http://www.ohtannenbaum.org/" target="_blank"&gt;Oh Tannenbaum!&lt;/a&gt;&amp;nbsp;which takes place in the &lt;a href="http://www.hfg-karlsruhe.de/" target="_blank"&gt;Karlsruhe University of Art and Design&lt;/a&gt;. The development was especially&amp;nbsp;interesting&amp;nbsp;since we made it within five days with a dozen of person with a very relaxed project management.&lt;br /&gt;&lt;br /&gt;Download the game for &lt;a href="http://dl.dropbox.com/u/626953/weihnachten2011/WINDOWS_Revenge_of_the_Christmas_tree.zip" target="_blank"&gt;Windows&lt;/a&gt; or&amp;nbsp;&lt;a href="http://dl.dropbox.com/u/626953/weihnachten2011/MAC_OSX_Revenge_of_the_Christmas_tree.zip" target="_blank"&gt;Mac&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The game is a beat'em up, where players control Christmas trees fighting against students. At the end, player characters face the Übertree, a huge, nasty Christmas tree, who set university's directors in captivity. Well, don't consider the story that much! Nonetheless, we won a &lt;a href="https://picasaweb.google.com/110476063603528281238/OhTannenbaum2011#5686854569562993698" target="_blank"&gt;special award for merits in ecological sustainability and deceleration&lt;/a&gt;, but I guess it's a joke from the jury ;)&lt;br /&gt;&lt;br /&gt;The game has been created with &lt;a href="http://lavalit.com:8080/" target="_blank"&gt;OpenBOR&lt;/a&gt;. It's a game engine specialized for beat'em ups, having ports on Windows, Mac... and several consoles such as Dreamcast, Wii and PSP! In addition, it does not require coding skills (though coding C-style scripts improves engine's default behaviors), so it may be a good start if you want to make games on such platforms. Although I have to say that you'll need good pixel artists...&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://picasaweb.google.com/lh/photo/JgaUqL1MPEkDBxFD4XRl1NMTjNZETYmyPJy0liipFm0?feat=embedwebsite" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img height="300" src="https://lh6.googleusercontent.com/-YxKdtvm9T2k/Tuvn77zbFjI/AAAAAAAADWE/97DaLsM8rdo/s400/revenge_selection.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Programming a level is quite easy: basically it consists in defining the position of each entity (enemies, obstacles, and so on) in plain text files. The engine already handles the AI for the enemies. But the supertree had predefined attack patterns and required a script to completely bypass the movements given by the engine. We coded a simple finite state machine, allowing it to move, to switch animation or to drop bombs.&lt;br /&gt;&lt;br /&gt;The graphics are GIF files. Images for an entity must have the same color palette to save ROM space and processing time (the engine focuses a lot on performance because it targets limited platforms). As always, an entity is defined in a text file and basically contains a list of available animations (which are themselves defined as a list of images). An offset can be declared with each image, that way they are consistent with the logical position of their entity. In the same way, images can have bounding boxes, attack boxes... While a simple image editor may suffice for these images, cut-scenes are animated GIF and an animation editor would be useful.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://picasaweb.google.com/lh/photo/67mqE6UvivnoK6DLN_MW8NMTjNZETYmyPJy0liipFm0?feat=embedwebsite" style="margin-left: 1em; margin-right: 1em; text-align: center;"&gt;&lt;img height="300" src="https://lh4.googleusercontent.com/-EtG1dTcjlbw/Tuvn7w7ZPfI/AAAAAAAADV8/FFJCCW3GYZ0/s400/revenge_1.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;We really lacked communication. It began as a classic Waterfall project (I was not the manager!) where artists deliver assets to be used by coders to build the game (by the way, coders design the level). The first graphics we received were PNG and as I said we needed GIF. Shadows were drawn on the images, but the engine already has its own ones! Even after that all artists have switched to GIF, the palettes were not coherent and I had to handle this problem until the end. Well, it would have been better when the artists would have asked to the coders details about what they have to do before (agile!). Hopefully, after figuring out these issues, the project ran better and we achieved to release the game for the exhibition.&lt;br /&gt;&lt;br /&gt;By the way, Jen and Jan have made their own game, &lt;a href="http://games.elorx.com/schmueckshooter" target="_blank"&gt;Schmück-Shooter&lt;/a&gt;, playable online. It's a third-person Christmas tree shooter, where the player has to decorate Christmas tree with a gun throwing Christmas balls and gifts. Nasty trees appear randomly and quickly move toward the player character. Sadly, nothing highlights these appearances and the players were very confused. It has been&amp;nbsp;developed&amp;nbsp;with &lt;a href="http://unity3d.com/" target="_blank"&gt;Unity3D&lt;/a&gt;, allowing to make it quickly... and&amp;nbsp;&lt;a href="http://hutonggames.com/index.html" target="_blank"&gt;Playmaker&lt;/a&gt;, to develop even faster. Playmaker is a visual state machine editor, allowing to drive logic with blocks and arrows instead of lines of code. I haven't tried it yet, but visual scripting is so more convenient for game designers... Available in the Unity Asset Store.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-3625942516601656949?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/3625942516601656949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/12/revenge-of-christmas-tree.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/3625942516601656949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/3625942516601656949'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/12/revenge-of-christmas-tree.html' title='Revenge of the Christmas tree'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh5.googleusercontent.com/-PaKOk1FPdpI/Tuvn7wf2NZI/AAAAAAAADWA/LfkrH_uHKDk/s72-c/revenge_start.png' height='72' width='72'/><thr:total>2</thr:total><georss:featurename>Lorenzstraße 15, 76135 Karlsruhe, Germany</georss:featurename><georss:point>49.00173130202436 8.383898735046387</georss:point><georss:box>49.00042930202436 8.381431235046387 49.00303330202436 8.386366235046387</georss:box></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-879369357688014503</id><published>2011-11-20T15:38:00.001+01:00</published><updated>2011-12-03T12:54:03.923+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libfirm'/><category scheme='http://www.blogger.com/atom/ns#' term='compilation'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>Kaleidoscope</title><content type='html'>I'm proud to release my own programming language &lt;a href="https://github.com/Bloutiouf/kaleidoscope" target="_blank"&gt;Kaleidoscope&lt;/a&gt;! With this powerful language, you can define functions, which can call another functions, add or multiply values, and... well, that's it. But look at this fabulous example:&lt;br /&gt;&lt;pre class="code"&gt;# imports&lt;br /&gt;extern input()&lt;br /&gt;extern print(v)&lt;br /&gt;&lt;br /&gt;# magic function&lt;br /&gt;def transform(a, b)&lt;br /&gt;    a * a + 2 * a * b + b * b&lt;br /&gt;&lt;br /&gt;main&lt;br /&gt;    print(transform(input(), input()))&lt;br /&gt;&lt;/pre&gt;Just kidding. This project is only a tutorial, and aims to use &lt;a href="http://pp.info.uni-karlsruhe.de/" target="_blank"&gt;libfirm&lt;/a&gt;, "&lt;i&gt;a library that provides an intermediate representation and optimisations for compilers. Programs are represented in a graph based &lt;a href="http://en.wikipedia.org/wiki/Static_single_assignment_form" target="_blank"&gt;SSA form&lt;/a&gt;.&lt;/i&gt;" Since I'm writing my master thesis on this theme, I've wanted to dig into a tutorial to understand the core concepts.&lt;br /&gt;&lt;br /&gt;Moreover, I used &lt;a href="http://www.gnu.org/software/bison/" target="_blank"&gt;Bison&lt;/a&gt; / &lt;a href="http://flex.sourceforge.net/" target="_blank"&gt;Flex&lt;/a&gt; for the first time, and this is pretty fun to program!&lt;br /&gt;&lt;br /&gt;Note: Kaleidoscope comes from &lt;a href="http://pp.info.uni-karlsruhe.de/firm/Neuestutorial" target="_blank"&gt;a tutorial written by the authors of libfirm&lt;/a&gt;, which is sadly not up-to-date with the latest versions of the library.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Parsing the code&lt;/h2&gt;The code needs to be cut into semantic tokens: it's the role of Flex. It is a &lt;a href="http://en.wikipedia.org/wiki/Lexical_analyzer" target="_blank"&gt;lexical analyzer&lt;/a&gt; generator, that is, you define token rules, and it creates a C function which can match these rules.&lt;br /&gt;&lt;br /&gt;For instance, given the rules&lt;br /&gt;&lt;pre class="code"&gt;"+"&lt;br /&gt;    { return '+'; }&lt;br /&gt;&lt;br /&gt;-?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?&lt;br /&gt;    { return DOUBLE_LITERAL; }&lt;br /&gt;&lt;br /&gt;[A-Za-z_][0-9A-Za-z_]*&lt;br /&gt;    { return IDENTIFIER; }&lt;br /&gt;&lt;/pre&gt;Flex will produce a function which transform the following code&lt;br /&gt;&lt;pre class="code"&gt;foobar + 42&lt;/pre&gt;into this series of token&lt;br /&gt;&lt;pre class="code"&gt;IDENTIFIER, "+", DOUBLE_LITERAL&lt;/pre&gt;Quite easy. Then comes Bison, a &lt;a href="http://en.wikipedia.org/wiki/Parser_generator" target="_blank"&gt;parser generator&lt;/a&gt;. Once again, you define rules to translate tokens into C code, and the generated parser will do the job. Here is an extract of the rules I use:&lt;br /&gt;&lt;pre class="code"&gt;expr : DOUBLE_LITERAL&lt;br /&gt;        {&lt;br /&gt;            // constant value&lt;br /&gt;            num_expr_t *expr = (num_expr_t *)malloc(sizeof(num_expr_t));&lt;br /&gt;            expr-&amp;gt;next = NULL;&lt;br /&gt;            expr-&amp;gt;which = EXPR_NUM;&lt;br /&gt;            expr-&amp;gt;val = $1;&lt;br /&gt;            $$ = (expr_t *)expr;&lt;br /&gt;        }&lt;br /&gt;    | IDENTIFIER&lt;br /&gt;        {&lt;br /&gt;            // variable&lt;br /&gt;            id_expr_t *expr = (id_expr_t *)malloc(sizeof(id_expr_t));&lt;br /&gt;            expr-&amp;gt;next = NULL;&lt;br /&gt;            expr-&amp;gt;which = EXPR_ID;&lt;br /&gt;            expr-&amp;gt;name = $1;&lt;br /&gt;            $$ = (expr_t *)expr;&lt;br /&gt;        }&lt;br /&gt;    | expr '+' expr&lt;br /&gt;        {&lt;br /&gt;            // addition&lt;br /&gt;            bin_expr_t *expr = (bin_expr_t *)malloc(sizeof(bin_expr_t));&lt;br /&gt;            expr-&amp;gt;next = NULL;&lt;br /&gt;            expr-&amp;gt;which = EXPR_BIN;&lt;br /&gt;            expr-&amp;gt;op = '+';&lt;br /&gt;            expr-&amp;gt;lhs = $1;&lt;br /&gt;            expr-&amp;gt;rhs = $3;&lt;br /&gt;            $$ = (expr_t *)expr;&lt;br /&gt;        }&lt;br /&gt;    ;&lt;/pre&gt;which parses an expression.&lt;br /&gt;&lt;br /&gt;As you see, I do not generate the final graph here, instead I construct an &lt;a href="http://en.wikipedia.org/wiki/Abstract_syntax_tree" target="_blank"&gt;abstract syntax tree&lt;/a&gt;&amp;nbsp;(AST). I used this solution because when parsing an expression, the context is still unknown, especially the function the expression belongs to. The AST would be something like:&lt;br /&gt;&lt;pre class="code"&gt;{&lt;br /&gt;    "which" : EXPR_BIN,&lt;br /&gt;    "op" : "+",&lt;br /&gt;    "lhs" : {&lt;br /&gt;        "which" : EXPR_ID,&lt;br /&gt;        "name" : "foobar"&lt;br /&gt;    },&lt;br /&gt;    "rhs" : {&lt;br /&gt;        "which" : EXPR_NUM,&lt;br /&gt;        "val" : 42&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;when represented in JSON :)&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Constructing the graph&lt;/h2&gt;Before parsing the code to compile, I initialize the libfirm library, and create a program representation inside the lib. Parsing shall complete this program with nodes, which describes the program in a logical way.&lt;br /&gt;&lt;br /&gt;When the tokens EXTERN, DEF or MAIN are parsed, I create a new function prototype. MAIN has its own prototype (no parameters, returns an int), whereas EXTERN and DEF have custom prototypes depending on the function they declare (parameters and return value are double).&lt;br /&gt;&lt;br /&gt;Moreover, DEF and MAIN define a function body, which is an expression. Actually, it's the&amp;nbsp;previously constructed&amp;nbsp;AST. So the tree is traversed to construct nodes. Here is the representation of the function graph for the first example's "transform" function:&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Bu3RYNgnpM4/TskgRbNrdHI/AAAAAAAADN8/6l7THDsmd_o/s1600/transform.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-Bu3RYNgnpM4/TskgRbNrdHI/AAAAAAAADN8/6l7THDsmd_o/s1600/transform.png" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;transform: (a, b) -&amp;gt; a*a + 2*a*b + b*b&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;A function has basically three blocks: a start block (prototype, etc.), a body block, and an end block. In the start block we see that the function takes two parameters (nodes 75 and 76) and returns only one (node 72). Green nodes are just links between blocks, unfortunately you'll have to guess these links.&lt;br /&gt;&lt;br /&gt;Note that the graph has been automatically optimized: the "2 * a" has been translated into "a + a" (node 84), which may be faster.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Generating the assembly file&lt;/h2&gt;Once the parsing is done, the program is transformed into another language (libfirm cannot directly generate executable file, it relies on assemblers to do this complex task). Here is the x86 assembly for "transform":&lt;br /&gt;&lt;pre class="code"&gt;# -- Begin  transform&lt;br /&gt;    .p2align 4,,15&lt;br /&gt;.globl transform&lt;br /&gt;    .type transform, @function&lt;br /&gt;transform:&lt;br /&gt;    .p2align 4,,7&lt;br /&gt;    /* .L66: preds: none, freq: 1.000000 */&lt;br /&gt;    pushl %ebp                       /* ia32_Push T[217:33]  */&lt;br /&gt;    movl %esp, %ebp                  /* be_Copy Iu[220:36]  */&lt;br /&gt;    fldl 8(%ebp)                     /* ia32_fld T[189:11]  */&lt;br /&gt;    fld %st                          /* ia32_fpush ANY[229:45]  */&lt;br /&gt;    fmul %st(1), %st                 /* ia32_fmul E[192:14]  */&lt;br /&gt;    fxch %st(1)                      /* ia32_fxch ANY[230:46]  */&lt;br /&gt;    fadd %st, %st                    /* ia32_fadd E[193:15]  */&lt;br /&gt;    fldl 16(%ebp)                    /* ia32_fld T[194:16]  */&lt;br /&gt;    fxch %st(1)                      /* ia32_fxch ANY[231:47]  */&lt;br /&gt;    fmul %st(1), %st                 /* ia32_fmul E[196:18]  */&lt;br /&gt;    faddp %st, %st(2)                /* ia32_faddp E[197:19]  */&lt;br /&gt;    fmul %st, %st                    /* ia32_fmul E[198:20]  */&lt;br /&gt;    faddp %st, %st(1)                /* ia32_faddp E[199:21]  */&lt;br /&gt;    movl %ebp, %esp                  /* ia32_CopyEbpEsp Iu[224:40]  */&lt;br /&gt;    popl %ebp                        /* ia32_PopEbp T[225:41]  */&lt;br /&gt;    ret                              /* be_Return X[171:22]  */&lt;br /&gt;    .size transform, .-transform&lt;br /&gt;# -- End  transform&lt;/pre&gt;That's it. Have fun with Kaleidoscope!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-879369357688014503?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/879369357688014503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/11/kaleidoscope.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/879369357688014503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/879369357688014503'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/11/kaleidoscope.html' title='Kaleidoscope'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-Bu3RYNgnpM4/TskgRbNrdHI/AAAAAAAADN8/6l7THDsmd_o/s72-c/transform.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-8008567350975190100</id><published>2011-10-25T16:38:00.000+02:00</published><updated>2011-12-17T00:24:40.814+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='Devmania'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='Löve2D'/><title type='text'>Pirates</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-yufu780qF44/TqbFje1ug7I/AAAAAAAACeA/VcPEeymoZw8/s1600/ship.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-yufu780qF44/TqbFje1ug7I/AAAAAAAACeA/VcPEeymoZw8/s1600/ship.png" /&gt;&lt;/a&gt;&lt;/div&gt;Some words about the prototype we developed at the &lt;a href="http://www.devmania.org/"&gt;Devmania 2011&lt;/a&gt; on the theme &lt;i&gt;Pirate&lt;/i&gt;. I don't provide links to download or play it because I don't feel I own it, read further.&lt;br /&gt;&lt;br /&gt;Edit: &lt;b&gt;all the games&lt;/b&gt; are available on &lt;a href="http://www.devmania.org/downloads/"&gt;the Devmania's website&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;We were a team of four. Our game was just named &lt;i&gt;Pirates&lt;/i&gt; (as many other ones). It was a vertical side-scrolling game where the player controls a ship and has to connect islands appearing randomly at the top of the screen in order to build a peer-to-peer network between them. Some enemy ships try to cut this cable, but fortunately you can shoot them with your cannons before that happens.&lt;br /&gt;&lt;br /&gt;The main drawback of the meeting was the lack of network connection. I couldn't have imagined a meeting of computer fans would provide no internet access. Well, now I can conceive it and therefore I will always put an Ethernet cable in my bag, and always attend to meetings with a switch. You should do the same as well!&lt;br /&gt;&lt;br /&gt;That implied we had to work with the only tools we had on our laptops. Because I developed &lt;a href="http://bloutiouf.blogspot.com/2011/06/magnetic-glues.html"&gt;Magnetic Glues&lt;/a&gt; on it, I still had the installation file of the &lt;a href="http://love2d.org/"&gt;Löve2D framework&lt;/a&gt;, so we decided to use this tool. Moreover, the documentation can only be found on internet, so the prototype provided a valuable starting point despite of its complexity, which has been dramatically reduced.&lt;br /&gt;&lt;br /&gt;Because we would not easily communicate our code (no version control), I thought it would be better to reduce the number of programmers and instead to produce some artworks. I am no artist, I can't produce great drawings, but the others have found them fun, so it's not a big waste of time. I mainly used &lt;a href="http://inkscape.org/"&gt;Inkscape&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Unfortunately I can't explain what they did on code because I took no interest to see it. I could just say that a common error has been repeated: at the end they rushed to provide instruction screen and to package the files. Anyway, I was not very productive on the project and I don't feel being really part of it, that's why I didn't uploaded it. Maybe a group member will do.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="https://picasaweb.google.com/lh/photo/dQ5Klgg8GlMlxhKRou8AJA?feat=embedwebsite"&gt;&lt;img height="266" src="https://lh5.googleusercontent.com/-ZGH9d_1aHcI/TprtUPSWQjI/AAAAAAAACTw/QdODKtEtq2c/s400/Presentation2.jpg" width="400" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Presentation of our game.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-8008567350975190100?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/8008567350975190100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/10/pirates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/8008567350975190100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/8008567350975190100'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/10/pirates.html' title='Pirates'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-yufu780qF44/TqbFje1ug7I/AAAAAAAACeA/VcPEeymoZw8/s72-c/ship.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-8023219042581224671</id><published>2011-09-06T01:02:00.000+02:00</published><updated>2011-09-07T04:40:55.657+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><title type='text'>Embedded terminal in websites</title><content type='html'>I release today &lt;a href="https://github.com/Bloutiouf/jquery.terminal"&gt;jquery.terminal&lt;/a&gt;, a &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; plugin to embed a terminal in web pages. It has several base commands and can be customized in order to add application-specific commands. It has a powerful operator mechanism to group command together (allowing to pipe commands and more combinations). And it is very, very geek.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bloutiouf.github.com/jquery.terminal"&gt;Try the demo online!&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I first coded this plugin two years ago, when Aurélien asked me for a terminal to administrate a game he made, without having to build a web interface. I thought it was a good idea and build a system which requires JavaScript and PHP to execute commands on the server side. Last weekend I found this code, and because I dropped PHP in favor of "all in JavaScript!" for months, I wanted to rewrite it. Here is the result!&lt;br /&gt;&lt;br /&gt;I really love the command flow, that the outputs of one command serve as additional arguments for another one. With real computer terminals, there are two input methods: arguments in the command line, or the standard input. I made here life much more easier: a single input way. Actually, it has been designed as a data stream with filters which can map values to other ones.&lt;br /&gt;&lt;br /&gt;It is the first time I build an execution tree. Because the syntax is really easy, it was not so difficult to parse and collect information. It mainly relies on state machines with a really few number of states. Another solution would have been to use a BNF grammar and a JavaScript parser. I don't know if it exists one, and anyway I thought it was too heavy. However, the final code is more complex to read, thus to maintain, than if it used BNF.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/Bloutiouf/jquery.terminal"&gt;Follow the development on GitHub.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-8023219042581224671?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/8023219042581224671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/09/embedded-terminal-in-websites.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/8023219042581224671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/8023219042581224671'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/09/embedded-terminal-in-websites.html' title='Embedded terminal in websites'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-6404670715006857011</id><published>2011-09-04T18:03:00.000+02:00</published><updated>2011-09-07T04:41:39.799+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JavaScript'/><category scheme='http://www.blogger.com/atom/ns#' term='internationalization'/><category scheme='http://www.blogger.com/atom/ns#' term='CouchDB'/><category scheme='http://www.blogger.com/atom/ns#' term='jQuery'/><category scheme='http://www.blogger.com/atom/ns#' term='CouchApp'/><title type='text'>Support for translation in CouchApps</title><content type='html'>I released two &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; plugins I made for a CouchApp: &lt;a href="https://github.com/Bloutiouf/jquery.tr"&gt;jquery.tr&lt;/a&gt; ans &lt;a href="https://github.com/Bloutiouf/jquery.couch.tr"&gt;jquery.couch.tr&lt;/a&gt;. These plugins allow to easily provide translation for your &lt;a href="http://couchapp.org/"&gt;CouchApp&lt;/a&gt;s. I was disappointed that until now CouchApps could only display text in one language (mostly English).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;jquery.tr&lt;/b&gt; is a generic plugin, that is its use is not restricted to CouchApp and you may use it with other applications (although other more convenient plugins exist in that case). &lt;b&gt;jquery.couch.tr&lt;/b&gt; is just a binding with CouchApp API. I have split the project in two plugins to keep a generic part.&lt;br /&gt;&lt;br /&gt;A fixed dictionary is used, so you can be sure of the relevance of your translation. By default, dictionaries shall be files inside the evently/widget directory, with language as name. The files contain either a JSON associative map, or a function which returns such a structure. With that function, you can choose different sentences according to parameters, e.g. to make them agree with numbers.&lt;br /&gt;&lt;br /&gt;This is not a full support for internationalization though, it can't  change interface or css direction attribute. It's still your job to  handle these application-specific cases.&lt;br /&gt;&lt;br /&gt;Integrating those plugins with your existing CouchApps is straightforward. Add &lt;span class="code"&gt;&amp;lt;script&amp;gt;&lt;/span&gt; references to the plugin files (you may use &lt;a href="https://github.com/carhartl/jquery-cookie"&gt;jquery.cookie&lt;/a&gt; as well, if you want to keep the last language used). Then, call &lt;span class="code"&gt;$.tr.language(language);&lt;/span&gt; to set the language which is use for further translations. Therefore, you may want to reload displayed widgets (for instance, &lt;span class="code"&gt;$('#account').trigger('_init');&lt;/span&gt; will reload the account widget)&lt;br /&gt;&lt;br /&gt;To illustrate the abilities of those plugins, I changed the default account and profile widgets (they should be included in any CouchApp) and translated the sentences into French. I can't say more than: it works!&lt;br /&gt;&lt;br /&gt;Note that I use &lt;a href="http://aefxx.com/jquery-plugins/jqote2/"&gt;jQote2&lt;/a&gt; as template engine rather than &lt;a href="http://mustache.github.com/"&gt;Mustache&lt;/a&gt;, which is so far not in the official repository, you should pull changes &lt;a href="https://github.com/Bloutiouf/couchapp"&gt;from this fork&lt;/a&gt; to import the feature. jQote2 allows to translate sentences directly in the template (&lt;i&gt;view&lt;/i&gt;), whereas Mustache forces to translate them in the data function (&lt;i&gt;controller&lt;/i&gt;), and I found the first case better.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/Bloutiouf/jquery.tr"&gt;Follow the development on GitHub.&lt;/a&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-6404670715006857011?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/6404670715006857011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/09/support-for-translation-in-couchapps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/6404670715006857011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/6404670715006857011'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/09/support-for-translation-in-couchapps.html' title='Support for translation in CouchApps'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-2524399162623630749</id><published>2011-08-21T00:04:00.014+02:00</published><updated>2012-03-15T04:51:07.385+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='shader'/><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='D'/><category scheme='http://www.blogger.com/atom/ns#' term='OpenGL'/><title type='text'>Introducing shaders in D</title><content type='html'>&lt;b&gt;&lt;i&gt;Update 3/15/2012&lt;/i&gt;: This code is quite old, consider my &lt;a href="http://bloutiouf.blogspot.com/2012/03/blur-effect.html" target=""&gt;new article Blur effect, which uses Derelict3, OpenGL3+ API and SCons&lt;/a&gt;.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Last weekend I was at the &lt;a href="http://www.evoke.eu/2011/"&gt;Evoke&lt;/a&gt;, the largest German &lt;a href="http://en.wikipedia.org/wiki/Demoscene"&gt;demoparty&lt;/a&gt; held in Cologne. I will release a story about this weekend, because it is the first time I go to a demoparty. Demos heavily rely on shaders to take advantage of the calculation power of GPU. But actually, I never wrote a shader program. I met another newbie, and we were willing to write some shaders and the associated OpenGL program to load them during the event. But because it would be too simple to do it in C++, I wanted to test the &lt;a href="http://d-programming-language.org/"&gt;D programming language&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;At first sight, D may look like C++. Well, its syntax is based on the C/C++ and it is quite easy to learn for developers used to this language family. But D improves some features of the C++, and sometimes it just breaks the old legacy. I would say it's to compare with C# and Java, but in another direction. I can't tell right now the advantage of D over these two languages because I'm inexperienced, but maybe after some prototypes...&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Update 22/8/2011:&lt;/i&gt; here's what Nical told us about D:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;&lt;span class="xk"&gt;it compiles VERY fast (productivity++)&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;&lt;i&gt;&lt;li&gt;&lt;span class="xk"&gt;you don't suffer from the C/C++'s horrible include system (productivity++)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt; the syntax is much clearer than C++ and is easy to parse for static analysis tools (software engineering++)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt; the behaviour of the language is more concistent than C++'s (ninja coding++)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt;it encourages unittesting (TDD++)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt; by design, the language does not let you do dangerous things unless you explicitly want to&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt; it has true support for parallel programming &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt; it is awesome&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt; it is fast (you can even turn off garbage collection in critical portions of code)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt;it has awesome metaprogramming facilities (that C++/boost is not  likely to have any time soon) and full compiletime introspection (on top  of which it is easy to build run time introspection)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="xk"&gt; and a  thousand of other things that makes you realize that C++ is a powerful  but inconcistent, error prone, ambiguous and unproductive language.&lt;/span&gt;&lt;/li&gt;&lt;/i&gt;&lt;/ul&gt;&lt;i&gt;&lt;span class="xk"&gt;Lacks a little bit of visibility on internet, some tutorials and dedicated libraries, though (yet it can use any C library).&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;I didn't want to write tutorials on this blog, but we had  pain to install the environment and do a basic program, so I write the  procedure we followed. This is for Windows and uses&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.digitalmars.com/d/2.0/index.html"&gt;DMD (the DigitalMars D Compiler)&lt;/a&gt;, a famous D compiler&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.dsource.org/projects/dsss"&gt;DSSS (D Shared Software System)&lt;/a&gt;, a build system which automatically computes the dependencies between libraries and programs&lt;/li&gt;&lt;li&gt;the libraries SDL and OpenGL via &lt;a href="http://www.dsource.org/projects/derelict"&gt;Derelict2&lt;/a&gt;, a project aiming at creating D bindings of C libraries.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;Installing the environment on Windows&lt;/h2&gt;You also have to install a SVN command-line interface because DSSS uses it during the installation. TortoiseSVN does NOT have this interface. I installed &lt;a href="http://sourceforge.net/projects/win32svn/"&gt;Win32SVN&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Go to &lt;a href="http://www.digitalmars.com/d/download.html"&gt;http://www.digitalmars.com/d/download.html&lt;/a&gt; and download the &lt;b&gt;dmd Windows installer&lt;/b&gt; on top of the page. Launch the installer: it asks you to choose components to install. Check D1 and D2. &lt;b&gt;&lt;/b&gt;Uncheck dmc unless you really want it. Continue the installation.&lt;br /&gt;&lt;br /&gt;Once installed, open a terminal: press the keys &lt;b&gt;Windows + R&lt;/b&gt;, type &lt;b&gt;cmd&lt;/b&gt; and validate.&lt;br /&gt;&lt;br /&gt;&lt;div class="terminal"&gt;C:\Users\MyUserName&amp;gt;&lt;/div&gt;&lt;br /&gt;Checkout the DSSS' repository somewhere, but avoid C:\dsss as you will understand later. In this example, I use the directory &lt;b&gt;D:\Code\dsss&lt;/b&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="terminal"&gt;C:\Users\MyUserName&amp;gt; d:&lt;br /&gt;D:\&amp;gt; cd Code &lt;br /&gt;D:\Code&amp;gt; svn checkout http://svn.dsource.org/projects/dsss/trunk dsss&lt;/div&gt;&lt;br /&gt;Type the following lines (the original ones are in Makefile.dmd.win). You may change the installation path at the last line.&lt;br /&gt;&lt;br /&gt;&lt;div class="terminal"&gt;D:\Code&amp;gt; cd dsss&lt;br /&gt;D:\Code\dsss&amp;gt; copy rebuild\defaults\dmd-win rebuild\rebuild.conf\default&lt;br /&gt;D:\Code\dsss&amp;gt; rebuild\rebuild.exe -full -Irebuild sss\main.d -ofdsss_int&lt;br /&gt;D:\Code\dsss&amp;gt; dsss_int.exe build&lt;br /&gt;D:\Code\dsss&amp;gt; dsss.exe install --prefix=C:\dsss&lt;/div&gt;&lt;br /&gt;Change your &lt;b&gt;PATH&lt;/b&gt; (see &lt;a href="http://www.windows7hacker.com/index.php/2010/05/how-to-addedit-environment-variables-in-windows-7/"&gt;http://www.windows7hacker.com/index.php/2010/05/how-to-addedit-environment-variables-in-windows-7/&lt;/a&gt; for example) by adding the directory &lt;b&gt;C:\dsss\bin &lt;/b&gt;and removing the directory &lt;b&gt;C:\D\dmd\bin&lt;/b&gt;. It's a little bit crazy, because dsss has to be compiled in D version 1, but then we want to use it with the version 2. You may remove the directory &lt;b&gt;C:\D\dmd&lt;/b&gt; as well because we don't use it anymore.&lt;br /&gt;&lt;br /&gt;Close the terminal and open a new one (to take the new &lt;b&gt;PATH&lt;/b&gt; into account). Checkout the Derelict2's repository (I still use &lt;b&gt;D:\Code&lt;/b&gt;).&lt;br /&gt;&lt;br /&gt;&lt;div class="terminal"&gt;D:\Code&amp;gt; svn checkout http://svn.dsource.org/projects/derelict/branches/Derelict2 derelict&lt;/div&gt;&lt;br /&gt;Compile the wrappers for SDL and OpenGL.&lt;br /&gt;&lt;br /&gt;&lt;div class="terminal"&gt;D:\Code&amp;gt; cd derelict&lt;br /&gt;D:\Code\derelict&amp;gt; dsss build DerelictSDL DerelictGL &lt;br /&gt;D:\Code\derelict&amp;gt; dsss install&lt;/div&gt;&lt;br /&gt;And you finally have your environment. Phew!&lt;br /&gt;&lt;h2&gt;Interfacing SDL and OpenGL with D&lt;/h2&gt;The bindings Derelict provides are very useful. They allow us to use the functions and constants as if it was written in C++.&lt;br /&gt;&lt;br /&gt;Here is a simple program we made, &lt;a href="http://blog.fedora-fr.org/bioinfornatics/post/D-Programming-with-SDL-and-openGL"&gt;based on this tutorial&lt;/a&gt;, refactored and expanded to load the shaders.&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;span style="color: black; font-weight: bold;"&gt;module&lt;/span&gt; main&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; core.&lt;span style="color: #006600;"&gt;time&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; core.&lt;span style="color: #006600;"&gt;thread&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; derelict.&lt;span style="color: #006600;"&gt;sdl&lt;/span&gt;.&lt;span style="color: #006600;"&gt;sdl&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; derelict.&lt;span style="color: #006600;"&gt;opengl&lt;/span&gt;.&lt;span style="color: #006600;"&gt;gl&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; derelict.&lt;span style="color: #006600;"&gt;opengl&lt;/span&gt;.&lt;span style="color: #006600;"&gt;glext&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; derelict.&lt;span style="color: #006600;"&gt;opengl&lt;/span&gt;.&lt;span style="color: #006600;"&gt;glu&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; std.&lt;span style="color: #006600;"&gt;file&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; std.&lt;span style="color: #006600;"&gt;stdio&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: black; font-weight: bold;"&gt;import&lt;/span&gt; std.&lt;span style="color: #006600;"&gt;string&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #993333;"&gt;class&lt;/span&gt; Shader&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; GLuint shader &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;~&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glDeleteShader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;shader&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;bool&lt;/span&gt; loadShaderFromFile&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;GLenum type&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; string filename&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: black; font-weight: bold;"&gt;try&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;   shader &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; glCreateShader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;type&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;   string code &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; readText&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;filename&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; loadShader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;code&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: black; font-weight: bold;"&gt;catch&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #aaaadd; font-weight: bold;"&gt;Exception&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;false&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;bool&lt;/span&gt; loadShader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;string code&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #993333;"&gt;const&lt;/span&gt; &lt;span style="color: #993333;"&gt;char&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;*&lt;/span&gt; ptr &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; code.&lt;span style="color: #006600;"&gt;ptr&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #993333;"&gt;int&lt;/span&gt; len &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; code.&lt;span style="color: #006600;"&gt;length&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  glShaderSource&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;shader&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;&amp;amp;&lt;/span&gt;ptr&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;&amp;amp;&lt;/span&gt;len&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  glCompileShader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;shader&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;true&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #993333;"&gt;class&lt;/span&gt; Program&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; GLuint program&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  program &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; glCreateProgram&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;~&lt;/span&gt;&lt;span style="color: black; font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glDeleteProgram&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;program&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; attachShader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;Shader shader&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glAttachShader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;program&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; shader.&lt;span style="color: #006600;"&gt;shader&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; link&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glLinkProgram&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;program&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; use&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glUseProgram&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;program&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;static&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; useFixed&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glUseProgram&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; GLint getUniformLocation&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;string name&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; glGetUniformLocation&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;program&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; toStringz&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;name&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt; &lt;br /&gt;&lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #993333;"&gt;class&lt;/span&gt; Display&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;uint&lt;/span&gt; height&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;uint&lt;/span&gt; width&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;uint&lt;/span&gt; bitsPerPixel&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;float&lt;/span&gt; fov&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;float&lt;/span&gt; nearPlane&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;float&lt;/span&gt; farPlane&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; Program program&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; GLint timeLoc&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;double&lt;/span&gt; time&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;this&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  height &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;800&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  width &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;600&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  bitsPerPixel&lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;24&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  fov &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;90&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  nearPlane &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: purple;"&gt;0.1f&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  farPlane &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;100&lt;/span&gt;.&lt;span style="color: #006600;"&gt;f&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  time &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  DerelictSDL.&lt;span style="color: #006600;"&gt;load&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  DerelictGL.&lt;span style="color: #006600;"&gt;load&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  DerelictGLU.&lt;span style="color: #006600;"&gt;load&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  setupSDL&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  setupGL&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  DerelictGL.&lt;span style="color: #006600;"&gt;loadClassicVersions&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  DerelictGL.&lt;span style="color: #006600;"&gt;loadModernVersions&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  setupShaders&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; setupSDL&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  SDL_Init&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;SDL_INIT_VIDEO &lt;span style="color: #66cc66;"&gt;|&lt;/span&gt; SDL_INIT_TIMER&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  SDL_GL_SetAttribute&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;SDL_GL_DOUBLEBUFFER&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  SDL_SetVideoMode&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;height&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; width&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; bitsPerPixel&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; SDL_OPENGL&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  SDL_WM_SetCaption&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;toStringz&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: red;"&gt;"D is the best"&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;null&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; setupGL&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glMatrixMode&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;GL_PROJECTION&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glLoadIdentity&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  gluPerspective&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;fov&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;cast&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #993333;"&gt;float&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;height &lt;span style="color: #66cc66;"&gt;/&lt;/span&gt; width&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; nearPlane&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; farPlane&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glMatrixMode&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;GL_MODELVIEW&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glLoadIdentity&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;private&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; setupShaders&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  Shader vertexShader &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;new&lt;/span&gt; Shader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  vertexShader.&lt;span style="color: #006600;"&gt;loadShaderFromFile&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;GL_VERTEX_SHADER&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: red;"&gt;"shader.vert"&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  Shader fragmentShader &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;new&lt;/span&gt; Shader&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  fragmentShader.&lt;span style="color: #006600;"&gt;loadShaderFromFile&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;GL_FRAGMENT_SHADER&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: red;"&gt;"shader.frag"&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  program &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;new&lt;/span&gt; Program&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  program.&lt;span style="color: #006600;"&gt;attachShader&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;vertexShader&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  program.&lt;span style="color: #006600;"&gt;attachShader&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;fragmentShader&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  program.&lt;span style="color: #006600;"&gt;link&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  program.&lt;span style="color: #006600;"&gt;use&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  timeLoc &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; program.&lt;span style="color: #006600;"&gt;getUniformLocation&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: red;"&gt;"time"&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;static&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; cleanup&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  SDL_Quit&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  DerelictGLU.&lt;span style="color: #006600;"&gt;unload&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  DerelictGL.&lt;span style="color: #006600;"&gt;unload&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  DerelictSDL.&lt;span style="color: #006600;"&gt;unload&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; update&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #993333;"&gt;double&lt;/span&gt; dt&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  time &lt;span style="color: #66cc66;"&gt;+=&lt;/span&gt; dt&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  glUniform1f&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;timeLoc&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; time&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;void&lt;/span&gt; render&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  glClear&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;GL_COLOR_BUFFER_BIT&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  glBegin&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;GL_TRIANGLES&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  glColor3f &lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glVertex3f&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;2&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glColor3f &lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glVertex3f&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;2&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glColor3f &lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  glVertex3f&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;1&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;,&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;-&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;2&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  glEnd&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  SDL_GL_SwapBuffers&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #993333;"&gt;public&lt;/span&gt; &lt;span style="color: #993333;"&gt;bool&lt;/span&gt; event&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  SDL_Event event&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #b1b100;"&gt;while&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;SDL_PollEvent&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;&amp;amp;&lt;/span&gt;event&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #b1b100;"&gt;switch&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;event.&lt;span style="color: #006600;"&gt;type&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span style="color: #b1b100;"&gt;case&lt;/span&gt; SDL_QUIT&lt;span style="color: #66cc66;"&gt;:&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;false&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: #b1b100;"&gt;break&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span style="color: #b1b100;"&gt;case&lt;/span&gt; SDL_KEYDOWN&lt;span style="color: #66cc66;"&gt;:&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: #b1b100;"&gt;if&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;event.&lt;span style="color: #006600;"&gt;key&lt;/span&gt;.&lt;span style="color: #006600;"&gt;keysym&lt;/span&gt;.&lt;span style="color: #006600;"&gt;sym&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;==&lt;/span&gt; SDLK_ESCAPE&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;false&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: #b1b100;"&gt;break&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;span style="color: black; font-weight: bold;"&gt;default&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;:&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: #b1b100;"&gt;break&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;true&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;span style="color: #993333;"&gt;int&lt;/span&gt; main&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt; Display display &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;new&lt;/span&gt; Display&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; TickDuration lastTime &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; TickDuration.&lt;span style="color: #006600;"&gt;currSystemTick&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; TickDuration newTime&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; TickDuration dt&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #b1b100;"&gt;while&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;display.&lt;span style="color: #006600;"&gt;event&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;{&lt;/span&gt;&lt;br /&gt;  newTime &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; TickDuration.&lt;span style="color: #006600;"&gt;currSystemTick&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  dt &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; newTime &lt;span style="color: #66cc66;"&gt;-&lt;/span&gt; lastTime&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;  lastTime &lt;span style="color: #66cc66;"&gt;=&lt;/span&gt; newTime&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  display.&lt;span style="color: #006600;"&gt;update&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;dt.&lt;span style="color: #006600;"&gt;length&lt;/span&gt; &lt;span style="color: #66cc66;"&gt;/&lt;/span&gt; &lt;span style="color: black; font-weight: bold;"&gt;cast&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #993333;"&gt;double&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;TickDuration.&lt;span style="color: #006600;"&gt;ticksPerSec&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  display.&lt;span style="color: #006600;"&gt;render&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;  Thread.&lt;span style="color: #006600;"&gt;sleep&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #0000dd;"&gt;10&lt;/span&gt;_000&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; display.&lt;span style="color: #006600;"&gt;cleanup&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;(&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;)&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt; &lt;span style="color: #b1b100;"&gt;return&lt;/span&gt; &lt;span style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span style="color: #66cc66;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #66cc66;"&gt;}&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Save this code in a file called &lt;b&gt;main.d&lt;/b&gt; and then compile it with DSSS:&lt;br /&gt;&lt;br /&gt;&lt;div class="terminal"&gt;D:\Code\shader-d&amp;gt; dsss build main.d&lt;/div&gt;&lt;br /&gt;It creates an executable main.exe, which works. If you plan to extend the application, you may write a dsss.conf (configuration file for DSSS). However it will stay light because unlike in C++, D mixes code and interface, and has a module / import system thus loads automatically other source files.&lt;br /&gt;&lt;br /&gt;But there are no shaders. Let's write them.&lt;br /&gt;&lt;h2&gt;Simple shaders in GLSL&lt;/h2&gt;Note that they are not compliant with GLSL 1.30, their purpose is just to show that it works.&lt;br /&gt;&lt;br /&gt;shader.vert (&lt;a href="http://en.wikipedia.org/wiki/Vertex_shader"&gt;vertex shader&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;uniform float time;&lt;br /&gt;&lt;br /&gt;void main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; gl_FrontColor = gl_Color * (0.5 + 0.5 * sin(time));&lt;br /&gt;}&lt;/div&gt;&lt;br /&gt;shader.frag (&lt;a href="http://en.wikipedia.org/wiki/Pixel_shader"&gt;fragment shader&lt;/a&gt;):&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;void main()&lt;br /&gt;{&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; gl_FragColor = gl_Color;&lt;br /&gt;}&lt;/div&gt;&lt;br /&gt;Save them on main.d's directory and relaunch the program.&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-qjln01xhrnI/TlAjp5yhFXI/AAAAAAAABYE/JUBI4xwgiR8/s1600/shader.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="250" src="http://4.bp.blogspot.com/-qjln01xhrnI/TlAjp5yhFXI/AAAAAAAABYE/JUBI4xwgiR8/s320/shader.png" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;A triangle which likes to disappear.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Voilà, we have a program in D which can load shaders. I will try to do some prototypes in 3D using shaders, and maybe in a few months I'll be able to write my own demo... :D&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Edit:&lt;/i&gt; &lt;a href="http://stackoverflow.com/questions/8482003/compiling-a-derelict-program-d" target="_blank"&gt;Someone has got issues&lt;/a&gt; following this tutorial on Arch Linux. Eventually it worked&amp;nbsp;at the end.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-2524399162623630749?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/2524399162623630749/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/08/introducing-shaders-in-d.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/2524399162623630749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/2524399162623630749'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/08/introducing-shaders-in-d.html' title='Introducing shaders in D'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-qjln01xhrnI/TlAjp5yhFXI/AAAAAAAABYE/JUBI4xwgiR8/s72-c/shader.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-4699456483381074496</id><published>2011-06-27T02:42:00.011+02:00</published><updated>2011-12-17T00:25:25.053+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GulaschProgrammierNacht'/><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='Löve2D'/><category scheme='http://www.blogger.com/atom/ns#' term='Box2D'/><title type='text'>Magnetic Glues</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-LP-VcYxuDyY/TgdzXD75LRI/AAAAAAAABE8/QhJ1Xjx49nM/s1600/aluminium+science.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="81" src="http://2.bp.blogspot.com/-LP-VcYxuDyY/TgdzXD75LRI/AAAAAAAABE8/QhJ1Xjx49nM/s200/aluminium+science.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;A Game Jam was organized during the &lt;a href="https://entropia.de/GPN11" rel="nofollow"&gt;11th GulaschProgrammierNacht&lt;/a&gt; and the theme was &lt;a href="https://entropia.de/GPN11:Gamejam" rel="nofollow"&gt;magnetism&lt;/a&gt;. Here is the prototype I made in a few hours.&lt;br /&gt;&lt;br /&gt;Windows users: &lt;a href="http://gamejolt.com/open-source/games/platformer/magnetic-glues/5526/" rel="nofollow"&gt;&lt;b&gt;quick play&lt;/b&gt; this game on Game Jolt&lt;/a&gt; (a .love version is also available for Linux and Mac users with Löve2D installed). &lt;br /&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/bloutiouf/projects/magnetic-glues"&gt;&lt;b&gt;Download&lt;/b&gt; the sources in my cellar&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I can't explain how the idea of making a &lt;a href="http://store.steampowered.com/app/400"&gt;Portal&lt;/a&gt;-like game appeared. Most probably it comes from the representation of magnetic dipoles, with red north pole and blue south pole, and I have quickly associated it with Portal.&lt;br /&gt;&lt;br /&gt;I had two main goals with this prototype:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;to test the physics library of Löve2D (actually a wrapper of &lt;a href="http://www.box2d.org/"&gt;Box2D&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;to test a code architecture with entities, behaviors and components (explications below!)&lt;/li&gt;&lt;/ul&gt;Box2D is an efficient though simple physics engine. As the name implies, it is specialized for 2D physics: body's position is x, y and angle values.&lt;br /&gt;&lt;br /&gt;An important feature for this gameplay is the ability to apply forces anywhere on the body, not only on the center (actually you may even choose an application point outside the body). But magnetic forces are omnipresent and Box2D was not designed to handle such forces. Worse, the magnetic force grows as the bodies come closer, so it is quite stressful when an object touches a magnetic glue. I limited the effect by restricting the forces to a maximal value, so they don't go to infinity.&lt;br /&gt;&lt;br /&gt;There is a trick in the second level (the data's filename is 4 because I made it at the end). I didn't manage to handle well forces on each side. In every case, the platform got stuck inclined. So the trick is to set the body's width to the distance between the two wall's bodies minus one pixel. You may show this by enabling the debugging mode in main.lua. That way, it shouldn't rotate too much.&lt;br /&gt;&lt;br /&gt;I said earlier that I had a discussion with Bruce about an architecture with entities, behaviors and components. I have given it a try with this prototype. Basically, an entity is composed of behaviors, and a behavior is composed of components. Theoretical examples of behaviors are "item", "movable" and "usable" while examples of components are "image", "(physical) body" and "input controller". Both entities and behaviors are game-specific, whereas components are given by the game engine. An entity may have at most one behavior of each type: having two identical behaviors makes no sense. However, a behavior may have several image or body components. For instance the player behavior has three images: the woman's body, her arm and the mouse cursor (because I thought a cursor would only appear when there is a player character).&lt;br /&gt;&lt;br /&gt;Moreover, there are two communication mechanisms: entities may send events to other ones, and components may send signals which are connected to functions inside their parent behavior (they can't cross to other behaviors). These two mechanisms have different semantics, so they can't be merged (but I may give it a try in the future...). In theory, events are related to gameplay and may even be run asynchronously (although not in this implementation). Signals allow rather instantaneous, direct accesses to data.&lt;br /&gt;&lt;br /&gt;But it was so complex. Entities ended to only have one behavior. In fact, entity and behavior could have been combined into a  single class. And right now, just two events are sent to entities. They don't come from another entity, they are triggered by collision handlers, so I could have used alternatives not to have events. As I said, I wanted to assess the architecture, but maybe the gameplay doesn't fit well. Or maybe the way I coded it caused that, at the end, I was totally fed up with this architecture and I made some direct accesses to data... The signal system works (I'm a fan of &lt;a href="http://qt.nokia.com/"&gt;Qt&lt;/a&gt; too, which heavily relies on signals-slots) but I am not sure it scales well when game engines become bigger.&lt;br /&gt;&lt;br /&gt;A word about graphics for last. I confess I tried to copy the style of &lt;a href="http://portal.wecreatestuff.com/"&gt;Portal: The Flash version&lt;/a&gt;. I made almost everything on &lt;a href="http://inkscape.org/"&gt;Inkscape&lt;/a&gt;, using a grid to align lines. Therefore I made them quite quickly. A disadvantage of Inkscape is the y-axis which points up, and in Löve2D it points down, so I had to change the basis to set the collision boxes (I could also change it in their declaration, but it may confuse values' meaning). Each image has a "layer" to draw the background behind the objects, the cursor over them, etc.&lt;br /&gt;&lt;br /&gt;Some things I'd change if I had to do it again:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I would really throw away behaviors, merging them with entities.&lt;/li&gt;&lt;li&gt;The asset format should be cleaned up.&lt;/li&gt;&lt;li&gt;There are some direct access to game and (physical) world (they are global). I would try to use no global variable. Maybe it's not a good practice, given that there is a single game and world.&lt;/li&gt;&lt;li&gt;There is a function in a level data. Perhaps it should better use a "script entity".&lt;/li&gt;&lt;li&gt;Some players reported a segfault. It may be related to physical bodies which seem not to be properly removed.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-JbSkSJp1eWY/Tge9C3CYpGI/AAAAAAAABFA/uaj6hzget1U/s1600/screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="496" src="http://4.bp.blogspot.com/-JbSkSJp1eWY/Tge9C3CYpGI/AAAAAAAABFA/uaj6hzget1U/s640/screenshot.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;By the way, my game jam's favorite game is &lt;a href="https://github.com/vrld/Princess"&gt;Princess by vrld&lt;/a&gt; (and I don't say that because I've kept in touched with him), made with Löve2D too. It was the only one to have a "story". Although very simple, the starting cut-scene and what the asteroids say took my breath away.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-4699456483381074496?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/4699456483381074496/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/06/magnetic-glues.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/4699456483381074496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/4699456483381074496'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/06/magnetic-glues.html' title='Magnetic Glues'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-LP-VcYxuDyY/TgdzXD75LRI/AAAAAAAABE8/QhJ1Xjx49nM/s72-c/aluminium+science.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-4004698609414910267</id><published>2011-06-17T03:21:00.010+02:00</published><updated>2011-12-17T00:25:15.193+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='SFML'/><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><category scheme='http://www.blogger.com/atom/ns#' term='Experimental Gameplay Project'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>Coglitz</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-R3qvnw7WzBE/TfqVliChW9I/AAAAAAAABAY/FSPr7GZ9SXM/s1600/coglitz+rabbit.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-R3qvnw7WzBE/TfqVliChW9I/AAAAAAAABAY/FSPr7GZ9SXM/s1600/coglitz+rabbit.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href="http://experimentalgameplay.com/"&gt;Experimental Gameplay Project&lt;/a&gt;'s theme for &lt;a href="http://experimentalgameplay.com/blog/2011/06/mashup-for-june-2011/"&gt;June 2011&lt;/a&gt; is mashup and my submission is Coglitz, a mix of games I like: &lt;a href="http://store.steampowered.com/app/26500/"&gt;Cogs&lt;/a&gt; and &lt;a href="http://store.steampowered.com/app/23120/"&gt;Droplitz&lt;/a&gt;. I just thought: what would result from this combination?&lt;br /&gt;&lt;br /&gt;Windows users: &lt;a href="http://gamejolt.com/open-source/games/puzzle/coglitz/5463/"&gt;&lt;b&gt;quick play&lt;/b&gt; this game on Game Jolt&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/bloutiouf/projects/coglitz"&gt;&lt;b&gt;Download&lt;/b&gt; the sources in my cellar&lt;/a&gt; (should compile on Windows, Mac OS X and Linux).&lt;br /&gt;&lt;br /&gt;This prototype is the opposite of Lifetime: no story, just gameplay.  I guess I have to see both extremes to find the right position.&lt;br /&gt;&lt;br /&gt;At  the beginning, I wanted the tiles not to rotate, but it has appeared it  is just too difficult. Anyway, you can still play with no tile rotation,  called "hardcore mode". It's interesting to note that I first try to  rotate the tiles and then to move them when rotation made nothing; my  playtests revealed that too. Well, Cogs is more intellectual than  Droplitz.&lt;br /&gt;&lt;br /&gt;I wondered if I could make it on Flash, using &lt;a href="http://www.stencyl.com/"&gt;Stencyl&lt;/a&gt; or &lt;a href="http://haxe.org/"&gt;haXe&lt;/a&gt;.  It's actually a typical Flash game. I've finally made it in C++ because  I discussed with Martin about doing some improvements on the sound  design, and he heavily relies on &lt;a href="http://www.fmod.org/"&gt;FMod&lt;/a&gt;. Therefore I used &lt;a href="http://www.sfml-dev.org/"&gt;SFML&lt;/a&gt;  and it works well. It includes wrappers on top of OpenGL and OpenAL, as  well as classes to handle windows and input. It also provides  network and parallel computing classes, but I haven't used this part of  the framework. But I have to say: avoid SFML for a tile-based game! As  you may see, the tiles are not perfectly aligned, though I attempted to  fix it. Among other things... &lt;i&gt;Update 6/22/2011:&lt;/i&gt; Rémi gave me a hint to this problem (as always he was right): SFML "smooths" images by default, actually by doing some linear sampling. I disabled that for the tiles and it looks better. Sorry for this incomprehension, SFML may work for tile-based games! I keep the old screenshot to let you compare (and because I'm too lazy to change it).&lt;br /&gt;&lt;br /&gt;As I tried to code it with iterations, I built some things which were  later removed, in order to simplify them. For instance, the coglitz used  at first a path system to move, a  graph with points and edges fixed on  the tiles. With the introduction of tile rotation, I thought it was too  complex to maintain this system, and I replaced it. Now the tiles are  simply described (image, and whether they have a pipe on each of their  sides) and coglitz move along the axis (it may introduces some  floating-point errors, but that's not important there). But as I was in a  hurry to get things done, I didn't refactor as much as I wanted. I  should clean the code in the next few days. Don't read the code right now.&lt;br /&gt;&lt;br /&gt;I made the graphics the last day. It didn't need to have nice tiles  before. I found wood is a nice theme, and the design quite easy to do.  Tiles in Cogs are already made of wood, and it just fits with the  gameplay.&lt;br /&gt;&lt;br /&gt;But I take back what I said last time: I took two days more to do  Coglitz than I needed for Lifetime, although with far simpler graphics.  So I deduce: if you want to do a game, it doesn't matter whether it has  good graphics, good gameplay or anything else. All you need is a clear vision of what you expect. Pretty reasonable, huh?&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-yKV4pOzDcoo/TfqVvmvOz-I/AAAAAAAABAc/h5kMhaakbnY/s1600/coglitz.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="496" src="http://3.bp.blogspot.com/-yKV4pOzDcoo/TfqVvmvOz-I/AAAAAAAABAc/h5kMhaakbnY/s640/coglitz.png" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;PS: the rabbit is just a joke for a friend. And yes, it's feature creep. Too bad.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Update 6/21/2011:&lt;/i&gt; Some things I'd change if I had to do it again:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;There is no entity system and I feel quite bad about that. At first it was great because I didn't want to lose time adding generic behavior when there is no need for it, but at the end there are too many dependencies (worse, cycles!) between the objects. It could have avoided hours of search for segfaults. So I would put some system to isolate the tiles and the coglitz. When a tile moves or rotates, an event is sent to drop coglitz on top of it.&lt;/li&gt;&lt;li&gt;Maybe the tiles and the board (actually the game) should share the same interface to give coglitz directions to follow. In the current implementation, I manually set the motion of a coglitz when it appear, then on every tile it checks the available directions and whether there is a collector at the bottom. With an interface, there would be no difference. It would make the code for the movement easier. &lt;/li&gt;&lt;li&gt;Last but not least, I would do another game, because this one is really not fun to play. Well, I knew it, and  the goal is to test experimental gameplays, but it's not so rewarding.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-4004698609414910267?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/4004698609414910267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/06/coglitz.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/4004698609414910267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/4004698609414910267'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/06/coglitz.html' title='Coglitz'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-R3qvnw7WzBE/TfqVliChW9I/AAAAAAAABAY/FSPr7GZ9SXM/s72-c/coglitz+rabbit.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-8935203877622648185</id><published>2011-05-27T17:55:00.010+02:00</published><updated>2011-12-17T00:25:05.545+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><category scheme='http://www.blogger.com/atom/ns#' term='Experimental Gameplay Project'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><category scheme='http://www.blogger.com/atom/ns#' term='Löve2D'/><title type='text'>Lifetime</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-6hi_GcJKdh4/Td-5LlukWhI/AAAAAAAAA3s/OFdMLzZ0YAM/s1600/10+boy+face.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/-6hi_GcJKdh4/Td-5LlukWhI/AAAAAAAAA3s/OFdMLzZ0YAM/s200/10+boy+face.png" width="158" /&gt;&lt;/a&gt;&lt;/div&gt;Lifetime is my first submission for the &lt;a href="http://experimentalgameplay.com/"&gt;Experimental Gameplay Project&lt;/a&gt;. The theme was &lt;a href="http://experimentalgameplay.com/blog/2011/05/zoom-in-may/"&gt;Zoom (May 2011)&lt;/a&gt; and it might be hard to make the connection at first sight. But this is what the theme inspired me.&lt;br /&gt;&lt;br /&gt;And I know this is no business practice but I don't want to pitch you the game.&lt;br /&gt;&lt;br /&gt;Windows users: &lt;a href="http://gamejolt.com/open-source/games/other/lifetime/5462/" rel="nofollow"&gt;&lt;b&gt;quick play&lt;/b&gt; this game on Game Jolt&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;&lt;a href="https://sites.google.com/site/bloutiouf/projects/lifetime"&gt;Go to my cellar to &lt;b&gt;download&lt;/b&gt; the game&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I have to say I am quite disappointed with this prototype. The artworks are for young children (though I wanted so), the code must be the ugliest one I made (I haven't wanted that!), and story is so simple. However, I did it so it would be stupid not to release it. Even if I failed to do a great prototype, I learned some lessons at least, and hopefully I will overcome them in my future games.&lt;br /&gt;&lt;br /&gt;I encountered some problems with my vision of entities made up of components. Among other component types, a GraphicComponent is only able to show a single image. And an entity can only have at most one instance of each type. What happens if an entity want to have several, independent graphical representations? Because I wanted the possibility to show two images at the same time during a cutscene. Finally this never occurred, but I still coded a class which is not part of the entity principle. I recently discussed with a friend about the entities in Warcraft/Starcraft and I will try next time to change a little bit my design.&lt;br /&gt;&lt;br /&gt;This was my first prototype with real dialogs. As I am quite influenced by my programming experience with &lt;a href="http://nwn.bioware.com/"&gt;NeverWinter Nights&lt;/a&gt;, my dialogs ended to be some generic containers used to launch scripts (there are dialogs which only run a function, with no text). But I didn't wanted to give a whole structure where just a text is required, so the format has become a mess. I will sanitize that problem in future prototypes... or just use fewer dialogs. &lt;br /&gt;&lt;br /&gt;I also realized that, when you are a developer, the bottleneck is everything but the code... therefore I won't do another game based on graphics before a while! There are 119 images in this game. The children's style helped to get them faster, but it's still a lot of work when you aren't an artist (achieved in four days along with studies!).&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-Zgnma_qqpYc/Td-5V6edEVI/AAAAAAAAA3w/8oU4wXwAV_Y/s1600/35+swing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="337" src="http://4.bp.blogspot.com/-Zgnma_qqpYc/Td-5V6edEVI/AAAAAAAAA3w/8oU4wXwAV_Y/s400/35+swing.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;i&gt;Update 6/21/2011:&lt;/i&gt; Some things I'd change if I had to do it again:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I would integrate the cutscenes into the entity system. The main reason is to avoid dealing with different systems on the same game. Rémi suggested that cut-scenes could be composed of several entities, one for each image, and another serving as a controller, reading a track and sending events to the entity-images. Another possibility is a component which can draw some images at the same time, but I guess it's trickier.&lt;/li&gt;&lt;li&gt;For the same reasons, I would put the dialogs into the entity system. Here one entity should be enough for the whole game, actually it would only have a DialogComponent. Sending an event "playDialog" to the entity "dialog" would load and play the dialog given as parameter.&lt;/li&gt;&lt;li&gt;To allow the previous points, I would have to write another Transform component. The current transform is influenced by the camera, but the entity-images and the text need to be independent of it, though they have still a position on screen. The goal is to have both game and UI using the same entity system. It would allow some tricky mechanisms, such as a button sending an event to the player-entity. But I don't really know how to split entities, i.e. draw the game entities at first, and then the UI in a second pass. Let's think about it. &lt;/li&gt;&lt;li&gt;The dialog format should not change, but using some helper functions I could hide the format to the designer/writer. I expected to work alone, but Brice copy-edited the dialogs and he had to deal with that mess.&lt;/li&gt;&lt;li&gt;If I had time, I would try to apply a low-pass filter on the music. Some players reported unpleasant ticks. I can't prefigure what it would result.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-8935203877622648185?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/8935203877622648185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/05/lifetime.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/8935203877622648185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/8935203877622648185'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/05/lifetime.html' title='Lifetime'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-6hi_GcJKdh4/Td-5LlukWhI/AAAAAAAAA3s/OFdMLzZ0YAM/s72-c/10+boy+face.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5451790455362512006.post-450562923022796141</id><published>2011-05-22T23:49:00.010+02:00</published><updated>2011-12-17T00:24:53.959+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='video game'/><category scheme='http://www.blogger.com/atom/ns#' term='Global Game Jam'/><category scheme='http://www.blogger.com/atom/ns#' term='Lua'/><category scheme='http://www.blogger.com/atom/ns#' term='prototype'/><title type='text'>The Split-Up Game</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ZLsbotyHO-Y/TdlsAdZ36SI/AAAAAAAAA24/ao_7hSg5zBg/s1600/splitup+logo.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-ZLsbotyHO-Y/TdlsAdZ36SI/AAAAAAAAA24/ao_7hSg5zBg/s1600/splitup+logo.png" /&gt;&lt;/a&gt;&lt;/div&gt;This is the game we made during the &lt;a href="http://globalgamejam.org/"&gt;Global Game Jam&lt;/a&gt; 2011 with Rémi and Fabian, on the theme Extinction.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://globalgamejam.org/2011/split-game"&gt;More advertising and &lt;b&gt;download instructions&lt;/b&gt; at the official page&lt;/a&gt; (supposed to run on Windows, Mac OS X and major Linux distributions)&lt;br /&gt;&lt;br /&gt;The idea took quite a long time to rise, but we wanted to try making an experimental gameplay (well, that is the goal of such prototypes, isn't it?) about relationship. Teammates felt excited about making a game that could really break up some relationships... no comments :)&lt;br /&gt;&lt;br /&gt;We wondered which technology we would use: HTML5 or Lua/Löve2D. After some tries, we chose &lt;a href="http://love2d.org/"&gt;Löve2D&lt;/a&gt;, mainly to facilitate asset management. This is a fabulous framework to create prototypes, as I have continued to use it for this purpose. In short, this framework allows to render 2D graphics and other primitive shapes (actually using OpenGL), sounds using OpenAL, keyboard/mouse/joystick input, and even physics simulation with a binding of &lt;a href="http://www.box2d.org/"&gt;Box2D&lt;/a&gt;. It uses Lua as programming language, therefore considerably accelerates the development... it would be impossible to do such a prototype in C++ within the same time. You should give it a try. Other prototypes mainly used &lt;a href="http://unity3d.com/"&gt;Unity3D&lt;/a&gt; and &lt;a href="http://www.adobe.com/products/flash.html"&gt;Flash&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Fabian did a really great job doing the assets. He (Rémi helped him too) modeled the rooms in 3D, then exported the scene with an orthogonal view as an image, and finally touched them up. Yeah there are some tricks, you might see that the room walls are slightly curved. But the result is amazing. The rooms are seen with a small angle, making the illusion of perspective, whereas the characters are straight because they have to turn in every direction and it was actually easier to do so.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-Mqcxu7856J8/Tdl6U2MFmEI/AAAAAAAAA28/WWsQtzzHpoI/s1600/bedroom.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="266" src="http://2.bp.blogspot.com/-Mqcxu7856J8/Tdl6U2MFmEI/AAAAAAAAA28/WWsQtzzHpoI/s320/bedroom.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Bedroom, first room of the game.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;The development was quite iterative, with no formal process. As we were grouped on the same tables and were only two developers, it was easy to discuss about our design and code. This might have annoyed other teams... Our design used two entity classes, Room and Item. Room is a description of a room, with their collision boxes (simple axis-aligned box collisions, no physics). Item is quite generic, actually a container for components which were described in the resource file for the room (Lua file too, no deserialization!). Finally, we used &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt; to version and share the code between us.&lt;br /&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-OWbRhd2eFaw/Tdl_JL8kjkI/AAAAAAAAA3A/Y7h0M2f9kJY/s1600/splitup+screenshot.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-OWbRhd2eFaw/Tdl_JL8kjkI/AAAAAAAAA3A/Y7h0M2f9kJY/s320/splitup+screenshot.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Beginning of the game. Some items are drawn over the background. But other interactions actually happen with items with no special graphics, like the library.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;It was my first real prototype, and now I love them. Such "contests" are a great occasion to learn about development by prototyping first. Because time is limited, one has to focus on the most important features to have a final package which works and is fun to play. Someone said &lt;i&gt;agile&lt;/i&gt;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5451790455362512006-450562923022796141?l=bloutiouf.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://bloutiouf.blogspot.com/feeds/450562923022796141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://bloutiouf.blogspot.com/2011/05/global-game-jam-2011-split-up-game.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/450562923022796141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5451790455362512006/posts/default/450562923022796141'/><link rel='alternate' type='text/html' href='http://bloutiouf.blogspot.com/2011/05/global-game-jam-2011-split-up-game.html' title='The Split-Up Game'/><author><name>Jonathan Giroux</name><uri>https://profiles.google.com/110476063603528281238</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//lh4.googleusercontent.com/-jM5E-AbyyLw/AAAAAAAAAAI/AAAAAAAABJY/8Nw-UK48Cd4/s512-c/photo.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-ZLsbotyHO-Y/TdlsAdZ36SI/AAAAAAAAA24/ao_7hSg5zBg/s72-c/splitup+logo.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
