SimplePaint8 v0.1 provides a simple way to draw shapes and export them as compressed strings for a game cart.
Intended use cases:
- Static backgrounds and other large images
- Splash screens
- Cutscenes
- UI elements
Controls:
- Left click: Select/Draw
- Right click: Cancel
- X: Press and hold, click to select tools or colors
- Y: Select pattern (to turn off the pattern, click on "pattern on")
- Arrows Left/Right: Move backward/forward in the step history
- Enter: Open menu and select "Export to string" to copy the image to the clipboard
Undo: Press the left arrow and then click anywhere on the screen to undo the last action.
Using the Exported Image:
The following functions are all you need, and it takes only 123 tokens and the exported string uses only 6 characters per shape.
function string_to_image(s) local draw_arr = {} for i=1,#s,6 do local a = {} for k=1,6 do add(a, ord(sub(s,i,i+5),k)) end add(draw_arr, a) end return draw_arr end function draw_this(draw_arr) local fn = {line,rectfill,circfill,ovalfill,line,rect,circ,oval} for i,v in ipairs(draw_arr) do local shape,col,x1,y1,x2,y2 = unpack(v) local a = fn[shape] if shape == 3 or shape == 7 then a(x1, y1, x2, col) elseif shape == 127 then fillp() elseif shape == 126 then fillp(ord(chr(x1))) else a(x1, y1, x2, y2, col) end end end |
Then you can simply use it as:
draw_arr = string_to_image"²ᶜ\n゛vU³⁷\"D⁵\0³⁷.G \0³⁷◀>ᵇ\0³⁷⁸:⁙\0³⁷⁙。ᵉ\0³⁷''⁷\0³⁷。 ⁷\0³⁷0゛ \0³⁷QE⁴\0³⁷KJ⁵\0³⁷]@⁸\0³⁷XK⁸\0³⁷m8⁷\0³⁷gD⁸\0³⁷k#ᶠ\0³⁷Y゛⁴\0³⁷Q ⁴\0³⁷[)⁵\0³⁷T*²\0³⁷rL \0³⁷}= \0²ᶜ I|e²ᵇ²/\0009²ᵇ⁴2\0<²ᵇ⁶5\0?²ᵇ⁸9\0C²ᵇ\n<\0F²ᵇᶜ@\0J²ᵇᵉC\0M²ᵇ▮G\0Q²ᵇ□J\0T²ᵇ⁘N\0X²ᵇ◀Q\0[²ᵇ「T\0^²ᵇ¥X\0b²ᵇ、[\0e²ᵇ゛_\0i²ᵇv(█;²ᵇt+█>²ᵇs/█B²ᵇr3█F²ᵇq7█J²ᵇp;█N²ᵇo?█R²ᵇnB█U²ᵇmF█Y²ᵇlJ█]²ᵇjN█a²ᵇiR█e²ᵇhV█i²ᵇgZ█m²³\0D\0c²³²F\0e²³⁵H\0g²³⁸J\0i²³ᶜM\0l²³ᶠO\0n²³□Q\0p²³◀T\0s²³」V\0u²³、X\0w²³゜Z\0y²³#]¹|²³&_⁴~²³)a⁷█²³-dᵇ█²³」Y\0█²³。Y\0█²³!Y\0█²³%Y\0█²³)Y\0█²³-Y\0█²³1Y¹█²³5Y⁵█²³9Y █²³=Y\r█²³AY■█²³EZ‖█²³IZ」█²³MZ。█²³QZ!█²³UZ%█²³YZ)█²³]Z-█²³aZ1█²³eZ5█²³iZ9█²³mZ=█²³Pcr█²³S`u█²³V]x█²³Y[{█²³\\X~█²³_V██²³bS██²³fQ██²³iN██²³lK██²³oI██²³rF██²³uD██²³xA██²³|?██²³○<██²\0¹ᵇ☉。²\0\0⁘⁸█²\0¹a●🐱²\0w¥●p⁵⁷7HUH" draw_this(draw_arr) |
Acknowledgement
The export functions is based on Storing Binary Data as Strings.
Update
2024-08-09
- cursor changes color based on the background (improved visiblity)
- coordinates on top of the screen
- fixed radius calculation for circ
Todo list
- import previously exported string
- add posibility replace drawing step instead of deleting all following steps
Very cool tool. Reminds me of a halloween themed point and click pico-8 game than handled its screens in a similar way.
Could be nice to be able to choose your up to 16 colors amongst the 32 instead of just the 16 standard ones.
this is so useful, im literally using this in my game right now.
i added a little x/y coords info area because im weird.
@RealShadowCaster Thank you! That is a great idea that would be very usefull.
@shrimpcat That's amazing! I'd love to see what you come up with. I considered adding x/y coordinates to the draw_this function but haven't thought of adding them to the tool itself (I will add it to the to-do list).
This is a really cool tool.
could definitely come in handy sometime in the future.
The one suggestion I would make though is to make the cursor change color when above red pixels so that you can see it.
I tend to lose the mouse cursor in red areas, so I'm using a magic color cursor instead :
circ(cursor.x, cursor.y, 1, rnd(16)) |
I also like the circle radius to depend on both x and y
local dist = flr(sqrt((arr.x1 - cursor.x) * (arr.x1 - cursor.x) + (arr.y1 - cursor.y) * (arr.y1 - cursor.y))) |
Warning, the dist formula is written multiple times in the code.
I'm also planning to mod in the 32 color support, but could wait for you if you intend to do it.
Remember that you can use palette 2 to have screen lines with another set of 16 colors as shown here :
https://www.lexaloffle.com/bbs/?tid=38565
This way you could display all 32 colors for the color selection.
You'll still have to set the palette 1 with the colors included in the drawing, so lots of palette and colors shuffling for the effect to work.
The string format encoding would stay the same, string2image also, but draw_this would have to change palette 1 along the way.
@RealShadowCaster Thank you for the notes. I fixed the distance/cursor along with a few other things.
I've been thinking about palette support, but I haven't found a good solution for adding it while keeping the token count low. Currently, when using it for my game, I manually change the palette in the code to match the one used in the game. Perhaps adding an import button to the menu, allowing users to input their palette as a string or a color picker with a palette export button and letting the user add it to the game themselves, could work well.
If you have any ideas on how to implement it, feel free to modify the code. If you send it to me, I'd be happy to incorporate it into this version.
If the token count on the game side is the most important, we can add a pal function to the list of commands, (internally, the user just chooses any 16 along the drawing, and the proper pal commands would be put at the start of the string and wouldn’t count as draws.
On the draw_this side, just an extra command for a few tokens.
On the string side, we’d pay 6 more length per color used outside the 0-15 range.(96 extra bytes per image at worst)
If this compromise sounds reasonable, I can start the implementation next week end.
@RealShadowCaster That sounds good to me! It would probably be good to track the colors separately and only push them to the draw_arr before the export and put empty pal at the start and end to keep it consistent and avoid any potential confusing behavior.
@voidgazerBon
I've been working on the 32 colors mod, and it's mostly done...
Due to personal reasons, I won't be able to work on it any more in the near future, So I'll post the WIP here.
Feel free to ask questions about the code and use is however you see fit. I'll be AFK but will still watch BBS on my phone.
Current limitations : palette 0 and 7 are considered always used ATM.
Since 1 is the usually the 1st unused palette entry, it's used 1st, so the menu that uses it as background changes color. It might look better to move the last available to palette 2 instead.
In draw_this, add ,pal at the end of the functions list.
pal (value 9 in the string) will be called with extra useless parameters that hopefully won't have new effects in the future.
the export part hasn't been tested much.
@RealShadowCaster I am sorry to hear that. I took a first look at it, and it is really good! Thank you!. I will try to finish it, but it will likely take me a week or two.
Unless @Nacorio or @shrimpcat needs the extra colors now, there is no rush.
You’ll have to check if I didn’t mess up the parameter order for pal statements, and aside from that, it’s mainly cosmetics: instead of using fixed black&white, use the darkest available in palette 1 and the lightest.
About pal 0, it would be simpler to consider is a forced black. You can’t choose the background color of fill patterns, so forced black makes extra sense. If you choose to allow color 0 change, some extra code in the palette optimisation will be needed, otherwise, is color 0 is used but is not the background fill color, the palette optimise step will put 0 back to entry 0 of the palette, resetting the chose backgroud fill color in the process.
Haven’t investigated yet, but line+fill pattern does strange things .
As you’ve yourself stated, string import and middle off the draw steam add/remove would be useful additions.
About cosmetics, ability to move onscreen info positions (move away from mouse maybe ?) and add black outline around text would allow better text readability regardless of draw color, and not have said text obscure the corner of the screen you’re currently working on.
About fill patterns, I’m curious : amongst the thousands possible 4 by 4, how did you choose your 26 ?
Edit :
@voidgazerBon
Another suggestion :use mouse wheel as a quick color change (stat(36) is -1 for scroll down and +1 for scroll up))
@RealShadowCaster, I am working on the alt pal, and I would like the user to be able to reset the colors to their original state. I thought I could preserve the first row of the color selection you added as the original colors, but I haven't been able to figure out how to do that. Do you have any tips on how I could achieve this?
As for the 'ability to move onscreen info positions,' that's a great suggestion! I'm adding it to the to-do list. :)
To be honest, I haven't put much effort into selecting the 26 patterns, as I haven't found them that useful in the end.
Thank you!
@voidgazerBon, I'm unsure what the "reset colors" is supposed to do.
If color selection is full screen, we have a lot of freedom.
If color selection is at the bottom of the screen and we have the very nice option to click on the still visible parts of the picture to choose color, then we're stuck with a line that contains all the colors used by the drawing, and we can place all the others where we want in the remaining squares. No way to keep the 0-15 1st line and 128-143 on the 2nd line for example. As soon as a "secret" color is used, it will have to be on the same line as black & white in the palette selection.
We could have a part of the color selection menu that would expand to a full screen color selection. If so, I'd recommand that layout
With some highlight on colors already in use.
It's visually coherent and has the 0-15 outside and the 128-143 in the middle. A very clever layout.
EDIT :
https://www.lexaloffle.com/bbs/?tid=3386
is where I first saw it, along with interesting pico palette related discussions.
EDIT again :
We could have the bottom 0-15 line plus 128-143 line at the bottom if we temporarily degrade the shown image by replacing every dark 128-143 color of the drawing by their 0-15 lighter version. We'd lose the "pick color in drawing option on top of image change". Not worth it in my opinion, except if it's an option that can be togged on and off. Like the fullscreen palette extension better.
Another idea could be to sacrifice one draw color and one palette color (max 15 colors in the drawing out of 31) and use gradient mode to show 31 colors vertically on the side of the screen. This way the order of the palette could stay fixed, but the color selectors would be rectangles half the height of current squares.
With that option we'd still have the pick color by clicking in drawing option.
Yet another edit :
Thought about another tradeoff if we want to keep the palette in place :
instead of scarifying the drawing colors during the palette display, we could sacrifice resolution and switch to 128l 64c 32colors mode when palette menu is visible.
The display code would be pretty wild : we'd have to do the regular display in the sprite sheet, then write code to convert that to the 32 colors display format into screen...(left half of the screen for the color index bits of the pixels, and right half of the screen memory for the palette selector bit). Might drop to 15FPS with is not a catastrophe for a drawing app. The color menu text would also need to use widened format to stay readable after losing half its horizontal resolution... But the color palette selector would stay fixed in whatever shape and arrangement we want, like the 32 colors plus placed inside the menu, and we'd keep the click in drawing to pick color. That's overall a big rework of the code.
And another one :
I'll finally be able to get some time home next week-end, feel free to post your WIP with explanations of what you did and what you need, I should be able to sqeeze an hour or two to work on it.
@RealShadowCaster Hi, I apologize for not replying sooner; I didn’t see the edits. I was working on other things and besides that I got stuck on how some of the memory stuff works with displaying both palettes at the same time, so I haven’t made much progress, but I tested different setups for the alternative palettes. I came up with two points:
a) Although I like the way you set up the optimal allocation for the selected color, I think it would be easier for the end user to select which color they want to replace with the alternative color. For example, they might want to select the colors before they even start drawing, or they may already know that they will not use a certain color but need all shades of green.
b) It should also be easy for the end user to reset the colors back. If they accidentally replace color 9 with an alternative color, there should be a button to reset it back.
@voidgazerBon, we could add another color indirection, so the color optimizations still occur, but the displayed order on the palette doesn't change visually, inside each row.
We could add a "manage palette ON/OFF" button. when ON, pairs of colors clicked swap places in the palette, if possible.
This would fill requirement a) of giving the possibility so select colors before drawing.
b) is more tricky. We could keep a history of palette changes, and the button would go back one step in the palette history and apply the palette if it's compatible with current drawing ?
How exactly wound you like the button to act, knowing that black, white and every used color will have to be placed somewhere in the first line.
@RealShadowCaster Here’s the version I’ve been working on. I’ve commented out the optimization for now to test some things, but I do like the idea of having an ON/OFF button.
For part b), I think resetting the currently selected colour to its original state would be sufficient for the OFF mode. For the ON mode, one option could be to add the original colour as the 'new' used colour at the top of the list. However, I’m not sure if that approach would feel intuitive.
On another note, I tried adding an import feature to let users resume work on an already exported image. It works if you manually paste the string into the code, but it doesn’t work with stat(4). I haven’t figured out the issue yet, but it seems like stat(4) is 'cleaning' or 'escaping' parts of the string.
\0 terminates the stat(4) string, and \r are deleted from the string. The other 254 characters work without problem
[Please log in to post a comment]