I started programming when I was 11 years old Wait, come back! , using BASIC on my Commodore 128. As soon as my dad entered “PRINT VLADA” into the prompt and the words “VLADA” appeared on the screen, I was hooked. My first experience with computer graphics came a couple of months after that, while I was devouring the Commodore 128 BASIC manual. The graphics chapter was my favourite, and for days I would experiment with animating parameters and drawing lines without clearing the screen buffer, resulting in my first fascinations with geometry. I had a friend from school who would come over and we would spend hours plotting the top-down schematics of fighter planes onto graph paper, and then some more hours manually typing in all those line coordinates into our BASIC program in order to draw the fighter plane on screen. It was majestic.
As soon as I got my first PC, I wanted to switch to a more powerful language. No widely available internet access back then, so my dad downloaded the “Teach yourself C++ in 21 days” book at work and printed it on a dot-matrix printer This was the format. He had to separate the book in three tomes, each roughly 10cm thick. . I overheard an older cousin telling my father that “perhaps I’m too young to learn C++”, so I really wanted to learn it. And I did.
In late high school, Linux came. I spent many years experimenting with different distros, learning how UNIX works, and this was the first time I got in touch with dynamic languages. I learned Ruby from Why’s weird and excellent book. I learned Python so I could write web crawlers and scrapers. I learned Lua so I could join the community around an open-source game and write a scripting interface for it. I learned PHP and SQL so I could get my first paid gig working on a local hardware seller’s backend system. I learned HTML so I could get a couple of hundred euros (Deutsche Marks back then) making a website for a photographer I met. I learned Java just for the fun of it, because it felt more modern than C++.
Learning a new language never presented a problem, and complaining about the lack of feature X in language Y did not happen.
Thinking about tools was not something I did back then. For most projects, there were only a couple of options available so choosing a language/tool was not a big deal. Today, however, I think about tools a lot, mainly because of the vast number of options available for any given project.
I got back into graphics programming through Processing. I’ve mostly used it as a distraction and for experimentation until my friend Jovan invited me to work on the CPN branding campaign. I still love Processing for being what it is, a simple and straightforward way to program graphics.
After that, I started working on games professionally. I got into Unity and C#, and was fascinated with its powerful “write once, deploy everywhere” model. However, several years of knee-deep working using that toolchain washed off the fascination and surfaced some of the underlying problems. Unity is built on very solid technology, but unfortunately almost everything is proprietary. It is a black box with a printed manual. If you don’t find the information you need in the manual, tough luck. You can join the other mystics on the forums, and participate in collective rituals of deducing what the black box is actually doing, since you have no other way to figure it out. As time progressed, less time was spent reading the manual, and more performing rituals.
During that period, I attended the excellent Clojure workshop at the Resonate conference in Belgrade. Karsten Schmidt showed us how functional programming can be used to concisely and beautifully express data transformations, and I have since used his thi.ng libraries in a couple of my projects.
Clojure has grown to be one of my favorite languages. It’s an excellent choice for doing complex data transformations while not bogging yourself down with “details” like strict types, ceremony, etc. For computational graphics and fast prototyping, it is an exceptional tool. The tooling around it, however, is not.
If you choose Clojure, you have chosen JVM by extension. I hold JVM in very high regard, and I think it is one of the most important pieces of technology in the last decade. For doing backend programming, choosing Clojure/JVM is a no-brainer. For doing graphics however, you can basically go down two different routes. You can either do it “the Processing way” by using Quil (which is awesome, by the way), or you can go the hardcore OpenGL way like Minecraft did. Using either one of those approaches always felt very clunky and heavy to me, because I could just feel the weight of that virtual machine whirring beneath my code.
If you choose ClojureScript, that’s where things get really hairy. You are technically a part of the JavaScript ecosystem, but you are like that weird kid in school who kind of has friends but no one really invites him anywhere. Here, you can also go the hardcore WebGL way (there are even some ClojureScript wrappers), or you can use an existing 3D abstraction library like Three.js. I’ve mostly used the Three.js approach because I really don’t feel like multiplying transformation matrices myself if I don’t have to. These are not the bad parts.
The bad parts are performance issues and lack of threads.
Abstractions/Complexity
Working “in the industry” for a long time (almost 15 years), I have in recent years sensed a mentality that everything needs to be modern, elegant, concise… philosophical even. If you’re starting a new project and you’re not using the latest language/environment/libraries, what the hell is wrong with you?
You are supposed to be sitting at the top of this mountain of abstractions, right? Use everything people before you have written and build on top of that? Stand on the shoulders of giants?
I felt I was doing all of these things while I was writing ClojureScript code. It felt really well. However, once the end result started taking a couple of seconds to render a semi-complex mesh, I got worried. The price you pay for having beautiful, concise syntax is paid in performance overhead if you’re not both careful and knowledgeable. It is very easy to fall prey to writing “natural” data transformations in Clojure(Script) without thinking about performance. Persistent collections will bite you in form of memory/GC overhead if you don’t understand how they work. These hidden underlying complexities have largely been ignored by the ClojureScript community because of its focus on front-end web code, which in most cases is neither computation- nor memory-intensive. Not many people use ClojureScript for doing realtime graphics, and those few who do are aware of these issues Just look at the pitfalls in that article! Use named functions instead of closures for map/reduce fns? I refuse! No one will tell you that in a Clojure book. .
A bigger problem for me is the lack of easy access to threads. Doing CPU-intensive generative graphics using only the main thread is laughable, no matter the toolchain. There are WebWorkers, but they are clunky even in JavaScript land. In ClojureScript land, you have to fight with:
- The compiler, which must produce WebWorker-compatible JavaScript code (this is actually much harder than it sounds)
- figwheel, which doesn’t support WebWorkers when hot-reloading code, and requires a compiler optimization level which is not compatible with WebWorkers (see above)
- The WebWorker data sharing model itself, which is written around JavaScript arrays and is completely against “the Clojure way” of handling data
- Your “WebWorker wrapper” library of choice, should you choose to use one of them
I have tried many different combinations and never got WebWorkers to work in a satisfactory way. Very basic examples work, but anything more complex just falls apart and either doesn’t work or deadlocks the application. I gave up, and very reluctantly shipped Aesthetic Engine 2 as a single-threaded application.
All of this is not the toolchain’s fault, but mine. I have chosen an obscure toolchain which lulled me with its elegance and iteration speed, while the actual runtime performance and capabilities suffered.
In 2017
I’m going back to my programming roots and choosing C++ with a thin graphics abstraction library underneath (openFrameworks or Cinder). Thinking about descending down the mountain of abstraction and working closer to the metal got me excited about fast realtime graphics again. No virtual machine, no garbage collector, no hidden costs, no workarounds. A fast language, native OS threads and GPU programming at your disposal. The community is also huge and the toolchains I’ll be using are open source. We’ll see how this setup fares in the long run.
I’ll still be using Clojure with Quil for fast prototyping and non-realtime graphics, mainly static imagery and print. This combo is currently powering the logo you see below.
Good times.