NOTE: This is a desktop app. The tools that make it interesting and its user interface (mouse/keyboard) make a web version not so useful. I've embedded it here in the spirit of general availability to Pico-8 users via splore.
Versawriter-8
Recently I released Mystery House (Remodeled), a ground-up rebuild of the first graphic adventure game. As part of the creation process, I wanted to redo the graphics using a workflow similar to the one that Roberta Williams did back in the day. Versawriter-8 was built so I could build Mystery House.
Everything in Mystery House (Remodeled) was drawn in Pico-8 using this tool. There are 45 unique "full screen" images, plus a couple of dozen objects, stored in about 10K using this tool and compression method.
What is (was) a Versawriter?
Roberta and Ken Williams used a device called a Versawriter on the Apple 2 to trace hand-drawn illustrations into Apple 2 hi-res graphics format. Ken wrote custom software for it that would "record" Roberta's tracing, then that was stored in a vector graphics compressed format. In this compressed format, only each point is recorded, and a line is drawn to connect it to the previous point. At run-time the computer would "play back" the recording and redraw the image. This allowed the limited storage of the floppy disk to hold all of the images needed for the game. This process would go on, conceptually, to become the AGI graphics format of the old Sierra games (i.e. don't store bitmaps, store instructions for drawing)
How to Use Versawriter-8
Versawriter-8 is quite simple in its scope and usage. You start in Draw mode.
In Draw mode
- Left-click to add points. Each consecutive click adds a point to the "island" (a series of continguous points)
- Right-click to end drawing the current "island"
- Left-click anywhere to start adding a new "island" to the drawing
- Drag a .png file (up to 128x88) into the draw area to use as a tracing template (you have control over positioning, draw color contrast, and more)
Space
switches to Edit Mode where you can fine tune your drawing a bit, and maybe save some bytes.
In Edit Mode
- Left-click-and-hold on a point to drag it around to a new position.
- Left-click-and-hold on a line to drag that "island" to a new position (only contiguous points).
- Right-click on a point to delete it
- Right-click on an "island" to delete it.
When you're done, C
key will copy the current image in its compressed string format to the clipboard.
A string copied to the clipboard can also be pasted in. Remember, Pico-8 needs permission to read the clipboard first, so CTRL-V to grant access, then V
to paste it in.
The format of a compressed string
Every point is stored as an x,y pair, with no delimiter between them (because they MUST be in pairs). We add 93 to X and Y (to shift their chr() values outside any P8SCII special characters) and that chr() is encoded in the string. Every "island" (a continguous series of connected points) is separated by chr(255).
Because image compression is the raison d'etre of this program, the total bytes/points/island count are always shown in the user interface. The byte count can be controlled by: fewer points, fewer islands. Try to think about how to draw efficiently. With practice you'll see how you can remove points without affecting the image quality, thanks to the low resolution of the screen.
To draw a compressed string
Feed the generated string to a routine like the one below to draw it (flip() if necessary). This one is 77 tokens. If you don't need offset or arbitrary color, it goes down to 53 tokens.
function draw_image(pic_str, offset, c) local offset = offset or {0,0} local c = c or 7 local islands = split(pic_str, chr(255)) for i in all(islands) do line() for p = 1, #i, 2 do local x, y = ord(i[p])-93, ord(i[p+1])-93 x += offset[1] y += offset[2] line(x,y,c) end line() end end |
The User Interface
Complete Tool List
- Drag-and-drop .png file (128x88 max) to use as a tracing template
space
: toggle between Draw mode and Edit moden
: clear the current document and start a new onex
: clear the tracing templatec
: copy image string to clipboardv
: paste clipboard string into canvas (Pico-8 requires CTRL-V first)p
: toggle point display on/offl
: toggle line display on/offt
: toggle template display on/offr
: toggle template "tracing mode" (monochromatic)-
: cycle through point color (for UI only)=
: cycle through line color (for UI only)s
: save your work to local cart (bottom-right light goes GREEN)a
: restore your saved work from local cartarrow keys
: nudge template position (in Draw mode); nudge all points (in Edit mode)
Self Assessment
Current Limitations
As the current version was built for my specific needs on a specific project, the main limitation of the program is in the draw area you can work in. It is specifically tailored to build Apple 2 hi-res graphics proportions, meaning a maximum draw area of 128x88, which leaves room for 6 lines of text below it; seemed reasonable at the time.
Additionally you cannot encode any color into the drawing. It is one-color only, but in your personal draw routine you could assign colors to drawings or even points within the drawing. You could draw multiple images on top of each other in different colors, to work around this limitation if you wanted.
Next Steps
I can think of four primary features that would make this more generally useful
- Set pen color for lines
- Allow flood fill
- Full screen image editing
- Better Edit mode (append points to existing island? group islands?)
Source code on GitHub
If you choose to make improvements to this, I would recommend basing them on pico-8 other existing graphics functions. Rectfills in particular would be pretty useful if the user wants to color in the image as that means far less individual lines.
Also, I don't know if you're just using it as a generic term, but a proper flood fill would be extremely slow. You'd be better off using a scanline fill so lines can be used for the actual drawing, but even then you're looking at a very slow operation. The reason is that checking the existing pixels on the screen or on the spritesheet is very slow. Ideally, a version using fills of that sort would somehow use preprocessing on the user-end.
@kimiyoribaka Yes, I am considering supporting native Pico-8 shapes. I did scanline fill tests on another project that never went anywhere, but I'm also quite fond of the original AGI techniques, which used lines and flood-fill. The slowness of the fills and watching the draw process was part of the charm of the original techniques, IMHO.
I would think that preprocessing would require inflating the size of the compressed image to hold the values that the preprocessing generates. I'm not entirely sure what you're envisioning there, but I'm currently favoring compactness over speed.
However, I'm not tied to anything whatsoever. It's currently just "What if I made it better? What would I want?" hypothesizing. Thank you for your valuable input.
I specified the preprocessing should be on the user-end because I figured you were going for compactness. What I mean by that is unpacking the string at the start of the game that's going to use it. If the actual function to draw the image takes some middle-ground input rather than the actual string, then all fills could instead be sets of normal instructions. If the fills are for 4-way flood fills or scanline fills, then the results can be lines, resulting in the same speed as what you have now. If the fills are 8-way or if the drawing algorithm is treating them as flood fills, then the instructions would need to be lists of points.
Of course this is all assuming that the images will be drawn from lua memory. It is also an option to just draw them to upper memory at the start of whichever game section needs them and then constantly swap between pages of image data, which I already know from multi-carting is fast enough for an rts. That's only an option for advanced users though.
Ah, I thought you meant on the Versawriter-8 user-end, not the player user-end.
Versawriter-8 image strings only define what needs to be done, not how to do it, and begins with the premise of imitating AGI graphics (like King's Quest). The drawing function is up to whomever implements it, so that can be as preprocessed (or not!) as the individual wants. I'd certainly provide a simple baseline draw function, but nothing in the image definition itself would require one implementation over another.
OMG, back in the day I made a DYI Versawriter from two potentiometers and some sticks and hooked it up to the Apple II game paddle port. It had unforgivable wobble to it, but it kinda sorta worked! Thanks for bringing that memory back.
[Please log in to post a comment]