Vector graphics experiments

While wondering what to do about The Balloonist, I've been having a go with some other tech on the device.

A few months ago I developed a vector graphics framework in Flutter for web and mobile games. Imagine what the old vector arcade games like Asteroids, Tempest, Star Wars, Battlezone etc. could look like on a device with a modern super-powerful cpu and fast line drawing. A new version of asteroids was the result of that, just for fun.

I've now ported most of the graphics engine over to C and have been seeing what sort of performance I could get out of the Cortex M7. At the moment all the arithmetic is in single-precision floats, but I think quite a lot of that could be changed to fixed point integers for maybe some more speed. With float math, this is the sort of thing you can do with a budget of 30 frames/sec:

rotation

Can't decide whether it could be a shooter or some kind of racing game. Ideas welcome!

8 Likes

Super great!

I would recommend more contrast (thicker lines, black objects?)

Thanks for the feedback! We are a little bit up against it from a performance point of view, as I've implemented a simple line-drawing routine for 1-pixel-wide lines but I guess we would need to fill rectangles for lines that were any wider. I'm not sure we have the budget for that.

Also, there's no filling going on here, so we couldn't easily colour the objects. The system is only drawing the lines, which is why it might be slightly more efficient than filled polygons on some scenes.

What is using up the rest of the cpu is clipping each line against any meshes that might occlude it.

I was planning dotted lines for the backgrounds and solid lines for any player or enemy ships in the tunnel. It seems to look ok on the real device, but agree that more contrast would be nice.

2 Likes

This is so cool. I love the aesthetic.

Idea from a non-programmer: Would it be too expensive to draw the lines closest to camera twice with single-pixel offsets for thickness? Then the midway lines with normal single-pixel thickness. And finally, keeping the further-away lines dotted for a "fog" effect.

1 Like

I am doing that in my game Cosmic Trash and indeed it's a bit of a frame rate killer. I am running at 40fps and without the fancy line work it's 50fps. I'm using Lua.

1 Like

Rather than drawing two lines, what you would probably do is double-up the pixels as you draw the line, would be better use of the CPU caches maybe. There are four different drawing routines, noon->1:30, 1:30->3, 3->4:30 and 4:30->6, so you could add a pixel perpendicular to the long side in each case.

However, as well as the performance hit, you would actually be moving the centre of the line 0.5 pixels. Don't know if that would be noticeable.

What might be the biggest problem is that lines with a significant z component (into the screen) would need to be split and drawn in parts, so that might add to your arithmetic budget.

Looking at the early arcade games that used vector graphics, I think Battlezone and Tempest could vary the brightness of their lines but not the width. Later on you have Star Wars, where it looks like the system could defocus the beam to create a wider line.

I was going for the look of those earlier games that had simpler vector displays, but the problem is that most players are too young to have seen them :grin:

Looks good! I enjoyed Tempest in the arcade with its rotary controller, and it could be a game that might suit the crank, don't know if you are using that?

I certainly am! Crank-first experience in this one.

ps: despite the looks... it's not Tempest, or even a shooter.

1 Like

That all makes sense.

Whether it ends up being dotted lines or more solid ones, I like where this is headed. Have you tried it out with white on black? That wouldn't slow things down, would it?

As someone who owns a Vectrex and an analog oscilloscope, I'm a big fan of vector graphics. I think even if people don't know about that look, they might just associate your graphics with SNES Star Fox, which could still be considered a win.

1 Like

Wow a Vectrex! I've never seen one in the flesh, just on youtube, but very cool. I remember them from back in the day but I don't think any of my friends had one.

It's funny about oscilloscopes, but even these seen to be all digital these days. Raster screens have truly taken over.

Since we are talking about Playdate, I did a quick hack to put a spline around the inside of the tunnel as a path for the player's plane and added crank to move left or right. I think it actually works really well, was worried that not being able to climb or dive would reduce player agency and fun, but the analogue nature of the controller really works well.

Also tried an inverse render and solid lines. My thinking with the white background is that overlays like score and lives can have a drop shadow and that can help to increase contrast and visibility. Inverse drop shadows are a little too visible I think, can be distracting.

rotation_version

2 Likes

This really changes the game (literal game-changer!) and will allow for much more interesting level design

2 Likes

Yeah, rasters have definitely won the battle, no question. I'm kinda glad because it makes vector graphics all the more rare and exciting.

This is so cool looking. I love it.

2 Likes

nice starting point!

Are you still clipping lines in the last screenshot?
You may want to invest some cpu into clipping lines - details are disappearing a bit too early when close to camera imho.

1 Like

Yes, what's happening is that each convex mesh in the scene is being trivially clipped against the near plane, if one vertex is too close then we drop the lot.

A better implementation would remove the overlapping vertices and add in the new geometry to make everything still be a solid shape. So a cube with one vertex overlapping the near plane would end up with seven faces instead of six, having a new triangular face coincident with the near plane, and three other five-sided faces.

It's taking a while to summon the motivation to do something like that :grin:

somehow I feel you are over thinking it?
clipping is done per face, not per ‘volume’.
iterate over each vertex, any vertex pair that is not on the same side needs to be cut and generate a new vertex.

see: abrash-black-book/src/chapter-65.md at master · jagregory/abrash-black-book · GitHub

Unfortunately, if I don't keep a complete volume together, it will break the hidden line algorithm. To test if a point is behind a convex mesh, part of the test involves the plane equations of all the visible faces in the mesh.

If there is a hole caused by a vertex being deleted by the near clip, which isn't filled by a replacement face, then lines behind will show through unpredictably.

I didn't realise Michael Abrash had written a book, that's a great link, thank you.

the clipped lines are for rendering only - keep the "world space" clipping untouched (if I understand correctly your alg.)

aaaah - got it - you are doing screen space clipping "in order" I guess.
tbh filling obstacles (w/ black) would be a lot simpler (and possibly faster!).

Not sure about filling, when you are only drawing lines, the "fill rate" is not really an issue, it's the clipping calculations that dominate. But the fill rate from the cpu on a general scene (ie. not Doom :grin:) is probably not going to be that great.

I originally implemented this algorithm in Flutter and gave a talk a little while ago to a group in London. If you want to read more, the slides are here: Flutter Line Engine - Google Slides

I do a bit of 3d on the playdate (see: Freds72 3d experiments & games) and you can be sure that your game will run at 30fps solid will filled polygons!

your technique is interesting, good luck making that a game proper!

1 Like

That Quake engine is very cool. Do you manage to run a z-buffer?

I'm wary of the painters' algorithm, as in the general case polygons cannot be sorted. The line engine I used can deal with mutually overlapping faces eg. A overlaps B overlaps C overlaps A.