Commit 3597b636 authored by PoroCYon's avatar PoroCYon

Blog post: Writeup: 512b rms intro: making of

parent 7d295d93
......@@ -13,7 +13,17 @@ mkdir -p "$DIR"
ADDENTRY=0
if ! [ -f "$FILE" ]; then
echo -e "# ${TITLE}\n\n" > "$FILE"
cat > "$FILE" <<EOF
---
title: ${TITLE}
blog-comment-link: ${FILENAME}
...
# ${TITLE}
EOF
ADDENTRY=1
fi
......
---
title: "Writeup: 512b rms intro: making of"
blog-comment-link: writeup-stallman-intro
...
# Writeup: 512b rms intro: making of
## Intros?
Intros are a subset of [*demos*](https://en.wikipedia.org/wiki/Demo_(computer_programming)),
programs that show an (often really cool) audiovisual presentation
"in real time" (i.e. while it is running). There's a whole subculture
built around them, called the [*demoscene*](http://vakondok.com/moleman-2-download/index.html).
An *intro* is a really small demo, often 64k (65536 bytes), 4k (4096) or
sometimes even smaller. This poses a challenge, as using clever hacks is
required to get anything done at all, and this is what makes it
interesting, and --- above all --- fun.
## The intro
This intro, called "I'd just like to interject for a moment", shows a
bitmap of Richard Stallman while playing the Free Software Song, all in
512 bytes. It was made as a 'bet' --- a friend didn't believe me I
could manage it --- but I entered it in the Alternative Platform compo
of this year's [Evoke](https://evoke.eu/2017/) demoparty. (It was my
first demoparty ever, and it was *very* awesome!)
I was originally planning on releasing a 4k intro, but I accidentally
overwrote the source code while working on it at the partyplace. In the
end, I endered this goofy thing instead. ("No prod, no party", as they
say.) It... ended up last, which was to be expected.
If you haven't seen it yet,
[here](https://www.pouet.net/prod.php?which=71555)'s the prod on Pouët,
there isn't a video capture available for the moment. (I should make
one sooner or later.) The source code can be found [on my GitLab
account](https://gitlab.com/PoroCYon/zss). (Yep, that's all in Lojban,
because I can.)
## Actual explanation
### Sound
The sound was the first thing I worked on. It's a simple
[bytebeat](http://canonical.org/~kragen/bytebeat/)-based
rectangleish wave, and the frequencies are read from a LUT, because I
couldn't find a function to generate the correct frequencies in time,
and the LUT compresses quite well anyway. It's not as esoteric as it
might seem.
The sound data is then written to standard output, which is piped to...
... `aplay`. Opening the `/dev/snd/*` files and calling all the relevant
ioctls would take too much space, and with my setup (see the
"Size-optimalisation" sub-heading), dynamic linking wasn't possible at
all.
### Visuals
This is a bit tougher. Using anything like SDL or OpenGL isn't possible,
and using raw X11 socket communication or raw DRI ioctls would take too
much space. There's only one thing left: Linux framebuffers, a relatively
unused (and, in my opinion, under-appreciated) part of the kernel.
Framebuffers are basically dumb pixel buffers, and they can be used
without having any 'graphics stack' (a VGA connector, for example, is
still required, for obvious reasons).
Setting one up is quite simple: just `open`ing a `/dev/fb*` file and
`mmap`ing it is enough to access and modify the pixels. A few ioctls
can be used to query for the size, etc. ([this
page](http://betteros.org/tut/graphics1.php#fbdev) covers it in detail),
but I ended up hardcoding these instead in order to keep it under 512
bytes. The rms bitmap was eating quite a lot of space.
That brings us to the other half.
The bitmap was drawn in the GIMP, and a simple C program was used to
pack it and transform it into something that didn't take several
kilobytes of space, and would play nice with the compression program.
The packed version is included in the final binary, and the code
simply dumps it (after resizing it) to the framebuffer.
### Size-optimalisation
The first prototype was written in C, and by the time I finished the
audio part, the final binary --- without compression, using
[BOLD](http://www.alrj.org/pages/bold.html)
--- was about 800 bytes, which is unacceptable!
(On a sidenode: I tried using Faemiyah's
[dnload](https://github.com/faemiyah/dnload/), but it seems to
segfault no matter what, and I haven't had the time yet to debug the
issue.)
I restarted from scratch, this time in 32-bit x86 assembly, using
[the hacks described here](http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html)
to achieve a small file size. I used as much packing on the data
as possible, but not many other assembly hacks were used, as my
knowledge on those is quite limited.
For compression, I used a simple dropper script for an
LZMA-compressed binary, something along the lines of the following:
```
sed 1d $0|lzcat>j;chmod +x j;./j|aplay
```
As you can see, I managed to squeeze everything within the 512 byte
limit, without too much of a hassle.
## A note about sizecoding on Linux
Sadly, Linux [seems to be a relatively negelected platform in the
demoscene](https://www.pouet.net/toplist.php?type=&platform=66&days=365&limit=50)
(one of my objectives is to change this), even though
a number of (sometimes very) active sceners do use it daily.
Then there's the case of sizecoding on Linux. An ELF header can
get quite large (unless made by hand, but then you're limited to
assembly, and I don't really have the time to do larger prods completely
in asm), and while it's relatively easy, framebuffer initialization
isn't exactly free either. I don't see 256b intros like the ones
currently made for MS-DOS coming to an objectively superior platform
anytime soon, but the 512-byte limit seems to be fine.
[Some](https://www.pouet.net/prod.php?which=51725)
[people](https://www.pouet.net/prod.php?which=51995)
[are](https://www.pouet.net/prod.php?which=58532)
[trying](https://www.pouet.net/prod.php?which=58389)
to work around this limit by compiling the code
at runtime (most of the time even using external libraries), which I
find quite hacky. Hence, sometimes [even
Python](https://www.pouet.net/prod.php?which=58666) is used.
Then again, most of these are still [XOR
textures](https://www.pouet.net/prod.php?which=57976),
[munching squares](https://www.pouet.net/prod.php?which=57976),
or a [variation thereof](https://www.pouet.net/prod.php?which=58805),
leaving lots to be desired.
Not that I'm *that* happy with my prod, either. It would've been much
more impressive if it didn't store a bitmap or a tone LUT. It might even
fit under the 256b limit if it was all 'magic' functions.
I'm currently exploring size-coded framebuffer intros more, and I'm
getting something ready for a next demoparty. Sadly, it won't be this
year's [Under Construction](http://under-construction.tum-party.net/),
though, as exams are getting in the way...
hello-world 2017-12-13 Hello, world! 69c41ec1-6053-48c8-84a6-347eaffe5e1f
rss-test 2017-12-13 RSS Test aa3f14ca-1701-4803-8db9-85d907597724
writeup-stallman-intro 2017-12-14 Writeup: 512b rms intro: making of 3370df4b-5cbc-42d2-8815-ae0048d9221d
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment