all blorgs

Termloop: pixel mode

I’ve been reading a lot about PICO-8 recently, and found it really interesting. For the uninitiated, PICO-8 is a ‘fantasy console’ - a games console which exists purely as a program and set of development tools, rather than a real piece of hardware. Developers can create games for PICO-8 which are small enough to be embedded directly into a .png image, which is really cool.

I’d been under the impression PICO-8 was actually a specification for a fantasy machine that anyone could build their own implementation of. Unfortunately this isn’t the case - it’s a closed-source program, which seems a bit odd considering the games have to be fully open-source and editable. Oh well. It did lead me to wonder if it’d be possible to get PICO-8 games playing in a terminal. That’s a whole ‘nother project, but I decided to tweak Termloop, my game engine, slightly, to make these sorts of games look better.

Normally, Termloop renders games in the way any other terminal application does. A cell is a rectangular shape, and has a background colour, a foreground colour, and a character. This means Termloop’s ‘pixels’ are rectangles rather than squares. Here’s a screenshot from the PICO-8 game Celeste.

Rendered using Termloop’s image viewer, it would look like this:

The image is very stretched, and we can only fit the lower half on-screen. What we can see, then, is that we’d ideally like to draw two square ‘pixels’ in each rectangular terminal character.

One solution would be to ask users to fiddle with their font settings so that their font’s widths and heights were similar. Obviously this isn’t ideal. Instead, we can use Unicode block elements.

▁ ▂ ▃ ▄ ▅ ▆ ▇ █

We want to fill half the terminal character with a different colour, so the one we want is called “lower half block”, and looks like this:

Of course, there’s a tradeoff to be made. In using these half-block characters, we use up the text value for that terminal cell. This means that, when using pixel mode, a Termloop game will have double the screen height, but will only be able to use cell background colours. For many games, this may well be worthwhile!

Changes to Termloop

The changes to Termloop’s code are fairly straightforward. First, a Screen struct now contains a boolean which says whether or not it’s in pixel mode - the default is false.

type Screen struct {
    // ... other stuff ...
    pixelMode bool
}

There’s also a new method, which a user should call right at the start of their program, before they call tl.Start().

// EnablePixelMode sets the screen to 'pixel mode' - giving double
// the canvas height while sacrificing character drawing ability.
func (s *Screen) EnablePixelMode() {
    s.pixelMode = true
}

Internally, the canvas needs to be represented as twice the height of the actual terminal. This is so developers can write their rendering code without needing to worry about whether or not they’re in pixel mode - as long as they’re just using Cell.Bg, anyway. The Screen.Resize() method is tweaked slightly.

func (s *Screen) resize(w, h int) {
    s.width = w
    s.height = h
    if s.pixelMode {
        s.height *= 2
    }
    c := NewCanvas(s.width, s.height)
    // blah blah...
}

Finally, the rendering process while in pixel mode needs to be slightly different.

func termboxPixel(canvas *Canvas) {
    for i, col := range *canvas {
        for j := 0; j < len(col); j += 2 {
            cellBack := col[j]
            cellFront := col[j+1]
            termj := j / 2
            char := '\u2584'
            if cellFront.Bg == 0 {
                char = 0
            }
            termbox.SetCell(i, termj, char,
                termbox.Attribute(cellFront.Bg),
                termbox.Attribute(cellBack.Bg))
        }
    }
}

Here, we step through the Cells in a Canvas column two at a time. We apply the background of the upper Cell as our terminal character background, and the background of the lower cell as the terminal character’s foreground colour. If the lower cell has no background colour, we don’t render the block character at all. This is because the ‘default’ colour for a foreground is different from the default background, so rendering the character with colour ‘0’ would result in a screen covered in stripes!

Pixel mode in action

To demonstrate the pixel mode, I’ve modified the Termloop image viewer example, as this seems the most logical example to use pixel mode in. All that needed to be added was one line in main(), like so:

func main() {
    if len(os.Args) < 2 {
        fmt.Println("Please provide a filepath to open")
        return
    }

    g := tl.NewGame()
    g.Screen().EnablePixelMode() // This is the new line!
    c := tl.BackgroundCanvasFromFile(os.Args[1])
    g.Screen().AddEntity(NewImage(c))
    g.Start()
}

That Celeste screenshot? It now looks like this in the viewer:

Much better! Everything is proportioned correctly, and we fit pretty much the whole image on-screen. If we tell the Pyramid example to use pixel mode, it looks like this:

Notice that the text that’s normally in the top-left of the screen is gone - we can’t render it in pixel mode, though if we were brave enough we could draw it in pixels!

Finally, here’s the obligatory Tempa T.

Termloop is open-source, and available on GitHub. You can have a chat to us on Gitter - we’re very friendly!

see comments

New site design

I’d got a little bit bored with the design on this website, and that boredom gave me no desire to write on it. Boo.

I was then reading about brutalist web design (it is very cool) and decided that what I wanted was the most minimal site design possible while still maintaining readability. This is it, or at least as close as a couple of hours’ work could get me.

The font is actually Courier, a monospaced font. I don’t really like Courier as a terminal font - I prefer Source Code Pro or something similar - but I think it’s actually quite nice to read on a page. You may disagree, but I don’t care because it’s my website so there.

Being super-minimalist in code samples probably would have impacted readability, so I’ve just gone the opposite way and used a theme I really like, even if it’s quite colourful.

function isJavaScriptNice() {
    console.log("Why do you even need to ask");
    return false;
}

The source code is available on GitHub, if for some reason you want to see it.

I’ll probably be making tweaks constantly over the next few days - suggestions in comments are very welcome.

For now, I’ve got a new fancy (as in, very much not fancy) home page. Go there. Go on.

P.S. Try looking at those ‘joel on stuff’ arrays on the home page on a mobile. Cool, huh? Yet another reason to use monospaced fonts absolutely everywhere. Including on birthday cards.

see comments

Good will toward men

It’s 2003. March, I think. I’m nine years old, sitting on a bunk bed in Stirling, crying my eyes out, utterly terrified. My parents are watching the news in the next room, and I’ve just overheard that Britain is going to war, against a country I’d heard of for the first time just a couple of months previously.

At this age, my only understanding of what war is or involves comes from recent history lessons at primary school on the second World War. Battles at air or sea, troop movements, supply chains, D-Day, the atomic bomb: these weren’t, to my memory, really discussed. The main focus was “life at home”, in particular the Blitz. At nine years old, my understanding was that any war would automatically have a home front. I thought - and struggled through gasps to explain to my bemused and more than a little concerned parents - that we were going to be bombed.

I was sixty years too late to ever experience something like a bombing, but the thought petrified me, and frankly still does to this day. I can remember little else from this time relating to the Iraq War - Game Boys and Bionicle were largely of greater concern at nine - but this scene in our Stirling hotel room is still irreversibly etched into my mind. I can remember, too, exactly what my mother said in an effort to calm me down:

“I don’t think it’ll ever come to that.”

What didn’t trouble me then, but does now, is that mum wasn’t entirely correct. While the horrors of war never visited us in sleepy Jordanstown, they kicked down the doors of people in Iraq who were not so very different from us. Estimates peg the number of civilian casualties as a result of this war at over 140,000. How many of these were nine year olds? I don’t know. We don’t hear their stories. I doubt primary school kids are told stories of the plucky Iraqis living through wartime. I doubt they’re taught to sing whatever the Iraqi version of “Kiss Me Goodnight, Sergeant Major” is. I doubt they’re making their own Iraqi ration books in art class.

One would think, given that our wars in recent years have not resolved the turmoil in Iraq, Afghanistan or Libya, that we’d have learned our lesson. We’d have learned that lobbing a load of explosives at a problem will at best not make it go away, and at worst will turn it into several problems, usually at the expense of thousands of innocent lives.

We know what ISIS - ISIL, Daesh, whatever - want. They’re not terribly secretive about what they’re up to. They have a magazine. You can read it online (I wouldn’t). They’re fairly up-front about the fact that military intervention aligns neatly with their goals. They’re also pretty bare-faced about their greatest concerns, and one of these is a lack of resources. Islamic State’s income is believed to largely come from the sale of oil from the oil fields it controls - who’s buying? Who’s selling them weapons? Who are their allies? Which of our allies are their allies? Why are we not more actively pursuing these answers?

I have read David Cameron’s proposal for the extension of our bombing campaign to Syria, and it did not make a convincing read. Too many unanswered questions about ground support or plans for after the campaign, not enough reasons to believe this will have any part in stopping IS. Several other nations have already been running bombing campaigns in Syria, and saw just how much of a difference that made in Paris. One might consider civilian deaths in warfare to be unavoidable, but the fact that we’re doing this for what seems, to 223 MPs and many others, to be no good reason utterly repulses me - and I do mean we. These are our elected representatives. We, the United Kingdom, have just legalised the murder of probably thousands of Syrian civilians, in exchange for what may well be just a token gesture of support to our allies. Well done, everybody. Drinks all round.

In the House of Commons tonight, there was laughter after the vote. When the result was announced, there were cheers. The fact that our politicians cheered the deaths of Syrian civilians chilled me to the bone, and I have no words to express just how much. I have already witnessed colleagues and acquaintances - not friends, thank God - post celebratory sentiments on social media. I hope these people know what exactly it is they’re celebrating.

This Christmas, just three weeks away, I have no doubt that David Cameron will once again profess to following the Christan faith. He might sit in a church in Witney at a carol service, listening to a choir deliver Glory To God from Handel’s Messiah. He might even sing:

Glory to God in the highest
And peace on earth.
Good will toward men.

And maybe, then, he’ll think there might be a nine-year old boy in Syria, watching the sky. He might think that, if this child’s mother is even with him, she won’t be able to tell him, “I don’t think it’ll come to that”.

I doubt it, though. Merry Christmas, Dave.

see comments