This is a quick-and-dirty, domain-specific vector drawing tool for making art for some of my own personal PICO-8 games. As such, it may not be very polished for general usage; adjust your expectations accordingly :)
PICO-8 cartridges have a very limited space (128x128 pixels) in which to store raster graphics so I made this because I needed a way to store many screens worth of art in a single cartridge.
Each painting is made up of several shapes. In order to keep this implementation small in both data storage and rendering code, only three different types of "shape" are supported:
Each shape has a color (one of the 16 PICO-8 colors).
The painting is saved as a hex string, like this:
05090a1c291830481c451e2f06080c2f26252a4012361c520c51
The format aims to be small, while still remaining easy to parse. These strings can be stored, parsed, and rendered from within a PICO-8 cart.
This program produces hexadecimal strings that you can copy and paste as a string into a PICO-8 program. See the file sample-use.p8 for PICO-8 code which parses and displays one of these strings. (Tip: The sample cart only uses a string, but it is possible to store painting data in the sprite sheet or other data regions of the cart)
The "painting" is a series of shapes, optionally followed by 1-3 fill patterns.
Each shape's data is laid out in the following manner:
# of bytes | description |
---|---|
1 | point count (max: 64) and fill-pattern index |
1 | color (first four bits are background color for fill-pattern) |
0b11000000
) are a fill pattern index. A value of
0 means the shape does not use a fill pattern. Values 1-3 refer to the index
of a fill-pattern (stored at the end of the painting data)0b00111111
) are the shape's point-count
(therefore there is a maximum of of 64 points in a shape)Then for each point, the following pair of bytes repeats:
# of bytes | description | note |
---|---|---|
1 | x-coordinate | |
1 | y-coordinate | saved 1 higher than actual value |
Note that 1 is added to the y-coordinate before it is saved, so when reading it, 1 needs to be subtracted from the value. This is done because the numbers are stored in an unsigned format and we want to allow for saving the y-coorindate as -1. The reason we want to be able to position things at -1 on the y-axis is that, because of the way the scanline rasterization algorithm here works, in order to draw a polygon which appears to touch the very top of the canvas, we actually have to position the top point(s) at -1 on the y-axis.
If the painting uses any fill-patterns, they come at the end, after the shape data. There is a maximum of 3 fill-patterns; the count is determined by observing the highest index to which any shapes' fill-pattern indices refer. If no shapes refer to any fill-pattern index, then this section is not written.
Each fill-pattern is stored like this:
# of bytes | description | note |
---|---|---|
2 | fill-pattern | follows normal PICO-8 fillp format |
Last is the transparency bits for the fill-patterns; these are all stored in a single byte to save space:
bit mask | description |
---|---|
0b10000000 |
transparency bit for fill-pattern 1 |
0b01000000 |
transparency bit for fill-pattern 2 |
0b00100000 |
transparency bit for fill-pattern 3 |
Read the lovely sections below and they will hopefully answer your every question:
This is a LÖVE program. If you don't know how LÖVE works, look it
up. The short answer is that you run love .
inside this
directory.
1234
qwer
asdf
zxcv
The keys are laid out in a 4x4 grid in order to mirror the layout of the
fill-pattern itself.Since this is a LÖVE program, it is only allowed to write to a folder inside a specific LÖVE folder whose location differs based on which OS you are using. Inside that folder you will find a "vector-paint" folder which contains your drawings, under the filenames you typed in the "save" dialog.
To load a previously saved painting, drag and drop the file onto the window using your OS's file manager UI.
Alternately, you may run the program with a command-line argument which is interpreted as a filename to load. The file must be inside the save directory, and the path must be relative to that folder.
To import a background image to use as a guide for tracing, drag and drop the image file onto the window using your OS's file manager UI.