Vecren: The Story Up Until Now. Part 2 of ??
(Note: this dev blog was started some 3 months into the process. These posts will share a tag, and are my attempt to reconstruct how we got to Present Day.)
So - now we had a renderer. It draws lines and points. Wrote some quick test programs hardcoding coordinates. Wrote a little exe test program - flies a triangle around on the screen, etc.- pretty standard stuff.
I started wondering what I might need to add, or build on top of this thing to actually make a game out of it. So I took Asteroids as my mental starting point. What do I need to make Asteroids? Being a dev for 25 years and a chronic overthinker - gonna need some way to debug, right? So let's write a library to render text to the screen. Plus if you recall from Part 1, I managed to get the little renderer I wrote back in the day drawing some text, so I was at least familiar with the task.
My goals were:
- Aside from setup, basically ONE call: drawText(x, y, text, font)
- a human-readable, and human-authorable font format. (since I had no tooling at this point, and as subsequent posts will indicate: I LOVE tooling, and writing tools. One of my favorite things EVER to program.)
- since I was going to have a human readable format - I felt like making sure it is diffable would be a good thing to have.
One of the first programming things I ever learned was Logo, in the 8th grade. If you don't know, Logo is a language designed for teaching programming and programming logic. You write small scripts which move a Turtle around on the screen, as it draws a trail behind it. There are some basic loop operators, and things - but it's enough to let you understand flow and logic. The linked page shows this example script to draw a Square:
repeat 4 [forward 50 right 90]or basically "do the following 4 times: move forward 50 units, turn right 90 degrees" - a nicely terse, readable loop. So I wanted something similar, even MORE simple, and even MORE terse. So I basically framed it according to how I would want to use the renderer to draw lines and points, in a way that is quickly readable/scannable/understandable, and I came up with the following:
# three utility commands:
C <r> <g> <b> # change the pen Color to rgb (0-255)
I <i> # set Intensity (brightness of the pen) to i (0.0 - 2.0)
E # End current draw operation.
# and the draw commands:
P <x> <y> # draw a Point at (x, y)
M <x> <y> # Move to (x, y) without drawing.
L <x> <y> # draw a Line from your current position to (x, y)
# the same square example from Logo, in vecdsl
# (assumes we are starting at 0,0 or screen center):
L 0 50
L 50 50
L 50 0
L 0 0
EAs you can see, I have no way to loop - and despite considering it a must-have, I have yet to have a need for it - which will be covered later.
Turns out some of my design decisions were validated when - I went looking for old arcade screenshots to see if I could recreate a font, and then it occurred to me that being the internet - the source code of some of those games is likely up somewhere. Friend, I was NOT disappointed, as not only did I find source code - I found an incredibly thorough annotated disassembly of Battlezone, with more information than you could possibly get through. After poking around, I found the glyph definitions for the font used, with a comment I LOVED:
"Character glyphs. Each glyph fits in a 16x24 cell whose origin is the bottom-left corner. The beam will be left at the initial Y coordinate, 8 units to the right of the character cell."
Hell ye, bottom-left origin bros! Bolstered by this, I pressed on.
# all of the properties in the header can be adjusted at runtime.
[Font] # only one of these allowed per file, obvs.
w 4 # all glyphs in a font must be the same w/h
h 4 # and....
kern 1 # all int params are specified in local grid (0,0) at bottom left
# coordinates.
scale 3.0
C 1.00 1.00 1.00
[A] # the blank line is a separator. this starts a glyph.
M 0 0 # reset location to origin
L 0 3 # draw up...
L 1 4 # ...and over...
L 3 4 # ...the...
L 4 3 # ...top, and...
L 4 0 # ...back down.
M 0 1 # move in position to cross the A
L 4 1 # Cross it.
E # glyph DONE. (also required.)
which gives us:

Fun, right? So, make an internal lookup of char 'A' to a set of draw ops, and boom.[1] Easy peasy. Now I can draw a letter A anywhere. The header specifies h/w and a value for kern - which does NOT mean what I thought it means, because I thought it meant how letters are spaced, so I intended it as "the number of grid units between each glyph" - which since all fonts are fixed width, should be straight forward. And it still DOES mean that, kinda - but it should just be called "spacing" or something else here, because kern is not quite right. My bad. ANYWAY - since I know all that stuff, I can draw strings - just do a little measuring based on scale/screen size, and soon I had a happy little text lib, drawing strings like it aint no thang. Time to grab some graph paper and go to WORK!
I quickly sketch out a graph paper font, open a text editor and start typing. Hmm. While the human readability is nice and it's easy to follow and understand, typing in all this stuff by hand was not a great authoring experience, but hey. Wasn't like I needed a million fonts, right? For now I just needed one I could print debug info with, and I had that. Remember? That's how ^^^ ALL THAT ^^^ got started: "I need a way to debug things, so some text would be nice" and here we are - WHOLE ASS meta language later. Like I said - I overthink things. And apparently, over engineer them.
Next up! Sprites.