Sunday, 16 September 2012

They have a fight, triangle wins

I'm just a dabbler in OpenGL really. Come to think of it, all I've really done is the most basic geometry and transforms, I've not even done texture mapping (though I've done that in DirectX). As I've had an interest in 3D graphics since college, it's something I want to get more practice at.

The Raspberry Pi supports OpenGL ES 2.0, which is also used in some of the newer mobile phones and tablets. The main difference between ES 2.0 and the OpenGL I'm used to is that it's built around a programmable pipeline, which in practise means that a lot of the core functionality I've taken for granted has been removed.

OpenGL uses little programs called shaders, which are used to configure the graphics hardware or software to apply various transforms or effects. They're written in the imaginatively named GL Shader Language (GLSL) - put the code into a string and pass it to OpenGL, it'll get compiled at runtime and applied to the appropriate data.

I've never done anything complicated enough with OpenGL to warrant writing a shader - simple stuff is taken care of by the core functions - but in ES 2.0 even the simplest of tasks requires a shader. For example, to project the 3D image onto a screen - something anyone doing 3D work is going to want to do - I'd normally set up the projection matrix. But that's gone in OpenGL ES 2.0, you have to put together the matrix yourself and manually apply it to each vertex with a vertex shader. Apparently this isn't unique to OpenGL ES - "desktop" OpenGL 3.1 has got rid of the projection matrix too - so this is something I'm going to have to get used to.

There are good reasons for this - it makes the API simpler and more flexible for advanced users - but it does make it harder for the beginner who has to do a lot of work to get the simplest thing up and running. It also means that the code isn't backwards compatible with OpenGL ES 1.1 and OpenGL 3.0, which is a pain as I like to move my code around onto different platforms.

I've not found a really good guide or tutorial for OpenGL ES 2.0 in C++ (perhaps I should write one?), but by taking snippets of code from various webpages I've managed to cobble together a "Hello Triangle!" It's quite epic at over 300 lines, but there's so much to set up I'd struggle to make it shorter. In the middle of  doing this my HDMI->DVI adaptor finally turned up, so I've been able to plug my Raspberry Pi into a monitor and get my red triangle in glorious 1280x1024, instead of the crappy interlaced PAL which as we all know is 720x576.

After that initial hump, getting something a little more complicated working was relatively easy. The tutorial code was all in C, so I made it a bit more C++-like with some juicy classes, call-by-reference, iostream instead of stdio, and getting rid of explicit mallocs where possible. "Hello Triangle!" was using the native display (i.e. no windows), so I added the option to use XWindows instead where it's available. Turns out there's a problem with the Raspberry Pi implementation of X which prevents this from working, so I've abandoned that for now. Then I learned how to do rotations with the vertex shader - which was fairly easy once you have the right matrix and can remember how to do matrix multiplication - and texture mapping with the fragment shader - which is far more complicated than I expected.

The end result was something which mapped a picture to a diamond shape and flipped it over and over, which I'm calling Phantom Zone. I've not worked out how to do screenshots without XWindows, so no pretty pictures this time. It's not much, but it's been useful for picking up the basics. Unfortunately there's a bug where it crashes the Raspberry Pi so badly that all remote connections are killed. I've no idea how I'd even begin to debug that one.

Now I've got the basics working, I'm coming up with ideas for something a bit bigger. When the Acorn Archimedes first came out it was bundled with a demo called Lander. Written by the legend David Braben, it later became the full game Zarch and was ported to other platforms as Virus. I think something along those lines would be fairly simple to do with the benefit of hardware accelerated graphics, at the very least I could get the terrain and craft working.

If that goes well I thought about turning it into a kind of reverse Defender, where you pilot a lone flying saucer and have to abduct people while avoiding increasingly aggrivated human defences. That's the kind of idea I can pick up and run with all day, indeed I've already lost a few hours of sleep thinking through the physics alone... but I'm not going to reveal any of the ideas here yet, I'll see how many of them I can put into practise.

Six entries in and I've written a lot about what I'm going to do, and time spent learning the basics, but I haven't actually achieved much. I'm kind of enjoying playing with software for the time being, though a part of me is itching to do the robot and knows that once I've drawn out some schematics I can start buying parts.