Friday 19 April 2013

ClojureScript & WebGL

A week ago I went to Hack the Tower, a JVM language hackathon (mostly Java/Scala/Clojure). Working with David, our agenda was to try to get a simple WebGL hello-world to work from ClojureScript.

For this I had previously found some example code written by Vishvajit Singh of the Los Angeles Clojure Users Group. We managed to make the code compile and work with modern versions of Leiningen etc. You can find the code on my GitHub and see it in action here.

Looking at the code, what I'd like to do next is to simplify things a bit and see how much of a hassle it would be to get rid of PhiloGL and instead implement that stuff in ClojureScript myself. (No offence to PhiloGL - it's great, but I'm not sure that using JavaScript libraries from ClojureScript is the most elegant way of doing things.)

Another simple thing would be to add a textbox that takes a URL pointing to an image file and then uses that image file as the texture. Or why not even take a URL pointing to a 3D object file, say a .3DS or a Blender file, and then render that. The possibilities are endless. And while I'm dreaming, how about adding sound - how would one go about doing that?

WebGL is awesome, need to explore it a bit more when I have time.

Monday 4 March 2013

A fun little function

Working through the backlog of potentially interesting bits I've been meaning to post about, I came across this one. Suppose you're given an unknown function, call it foo, and asked to figure out what it does. The function takes as parameters four ints and returns a string. Experimenting a bit, you figure out that if the ints are small and non-negative, the function returns nice ASCII art:
> print(foo(4, 12, 4, 10))

        +---+        
        |   |        
+-------+   +-------+
|                   |
+---+               |
    |               |
+---+           +---+
|               |    
+-------+   +---+    
        |   |        
        +---+        

> print(foo(24, 5, 24, 11))

+-------+            
|       |            
|       +-------+    
|               |    
+---+           +---+
    |               |
+---+           +---+
|               |    
+-----------+   +---+
            |       |
            +-------+

Question 1: what does the function foo do?

The input ints are interpreted as the edges of a puzzle piece, which is then printed out. Viewing the ints in their binary form, it's easy to see that the orientation of the edges is clockwise, north-east-south-west:
      -->
   +-------+            
   | 1   1 | 0   0   0  
   |       +-------+       |
   | 1   1   1   1 | 0     |
   +---+           +---+   v
^    0 | 1   1   1   1 |
|  +---+           +---+
|  | 1   1   1   1 | 0  
   +-----------+   +---+
     0   0   0 | 1   1 |
               +-------+
                <--
Here of course 24 = 11000, 5 = 00101, 24 = 11000 again and 11 = 01011. The ordering is a bit arbitrary and there's an overlap between the first and last bits of each int, but that's all fine.

Question 2: how would you implement the function foo?

A simple scanline algorithm should be good for this. First convert the given ints, interpreted as 5-bit numbers, into a 5x5 boolean matrix for simplicity. (Note that the center 3x3 of each puzzle piece is always filled, so it's just the given 4 edges that make this interesting.) After this start at, say, the upper left corner, and going through each row in the matrix left to right, check the values for this cell and the relevant neighbours and draw accordingly. (Define the cells outside the matrix to have the value 0.)

Now since you're processing the cells in order, top-to-bottom and left-to-right, it's sufficient at each cell to just consider the upper, upper-left and left neighbours. This gives you in theory 16 different cases. Sketching them out you'll find 5 distinct cases (or 4, depending on how you look at it); or you could just notice that there are 4 main cases depending on whether you've just crossed a horizontal edge, vertical edge, both or neither, and then one more case depending on whether you've just ended or started a both-horizontal-and-vertical cross point.

Instead of going through the algorithm in more detail, here's the link to an implementation on Github. I wrote the refactored version in slightly scruffy C for some reason, after noticing that the first implementation I had done a while back was amusingly bad. To test it out, simply say "make" and for some examples, see the "test" script. (No unit tests this time, sorry.)