30.10.14

Trigonometry in awk

I've been doing a lot of work with OpenGL recently, attempting to get some glBegin()/glEnd()-era 'rendering' code into some kind of shape where I can port it from desktop OpenGL to mobile and web platforms running OpenGL ES or WebGL. This basically meant throwing the existing code into a well, burning it, learning how to OpenGL properly and starting again, but that's all going quite well—I've even started writing shaders! 1

This post, however, is not about that. Having got to a point where I have a basic 2D GL3.0/GLES2.0 framework in place, I wanted to actually draw something. Triangles are almost too easy to draw, and squares aren't much harder (you can either use glDrawArrays(GL_TRIANGLE_STRIP) or glDrawElements(GL_TRIANGLES)).

So, with mastery of 3 and 4 vertex shapes, I wanted to move on to the next challenge, which is obviously... a pentagon. But how to figure out the co-ordinates? The math behind regular polygons is pretty straightforward, so we just need to take sines and cosines of some angles. I thought that jumping into C++ for this was a bit over the top, and I wasn't in the mood to mess around with any 'batteries-included' interpreters. I just want something quick, light and iterative—agile, if you will. I wonder whether awk has any numeric capabilities...

Spoiler: It does!

#!/usr/bin/awk -f
BEGIN {
    PI = 3.141592654

    if("" == (SIDES = ARGV[1])) {
        SIDES = 5
    }
    if("" == (COMMENT = ARGV[2])) {
        COMMENT = "#"
    }

    print COMMENT " " SIDES "-sided regular polygon..."

    print COMMENT " vertices"
    for(n = 1; n <= SIDES; n++) {
        A = 2 * PI * n / SIDES
        printf "%.2f, %.2f,\n", cos(A), sin(A)
    }
    print COMMENT " texcoords"
    for(n = 1; n <= SIDES; n++) {
        A = 2 * PI * n / SIDES
        printf "%.2f, %.2f,\n", (.5 + cos(A)/2), (.5 + sin(A)/2)
    }
}

One of the niceties of awk is that there's no operator for string concatenation, you just glom string variables and constants together next to each other and it 'just works', which makes print statements a lot less noisy than most other languages. Another nice thing is that printf is available, and works exactly as you'd expect it would. Other than that, we only really need sin(), cos() and the ability to loop, and we're finished.

When run, this spits out data for vertex coordinates (ranging -1.0 to 1.0) and texture coordinates (ranging 0.0 to 1.0) for each point around the edge of a regular polygon (defaulting to a pentagon if no parameters are given).

$ ./poly.awk
# 5-sided regular polygon...
# vertices
0.31, 0.95,
-0.81, 0.59,
-0.81, -0.59,
0.31, -0.95,
1.00, 0.00,
# texcoords
0.65, 0.98,
0.10, 0.79,
0.10, 0.21,
0.65, 0.02,
1.00, 0.50,

It can generate coordinates for any number of sides, and there's even an optional parameter to change the comment syntax, so you can just copy and paste the output into the vertex array literal of your language of choice.

$ ./poly.awk 3 //
// 3-sided regular polygon...
// vertices
-0.50, 0.87,
-0.50, -0.87,
1.00, 0.00,
// texcoords
0.25, 0.93,
0.25, 0.07,
1.00, 0.50,
$ ./poly.awk 6 --
-- 6-sided regular polygon...
-- vertices
0.50, 0.87,
-0.50, 0.87,
-1.00, -0.00,
-0.50, -0.87,
0.50, -0.87,
1.00, 0.00,
-- texcoords
0.75, 0.93,
0.25, 0.93,
0.00, 0.50,
0.25, 0.07,
0.75, 0.07,
1.00, 0.50,

awk's execution model is geared towards reading files line-by-line, extracting patterns and processing them, so this isn't really playing to its strengths. But nevertheless, treating it like a high-level, loosely typed version of C, I was able to get from idea to implementation to refinement in about 10 minutes. (And then I was able to render a coloured, shaded OpenGL pentagon and it made me happy. I am easily pleased.) I think awk is a useful tool to get to know, seeing as it's almost certainly already installed on your machine2.

The Android NDK goes as far as to use awk to build a full XML parser (of sorts), which is entertaining, if not a little bit bonkers.

Here's a terrible-looking graphic of the Emscripten-powered pentagon!



1 I should probably write about cross-platform shader development at some point, it's all manner of fun!
2 Not you, Windows user! You'll have to make do with PowerShell.