Hello,
I’m working at my 1st Arduboy project. I’d like to create a simple pixel drawing app where user can make pixels black or white moving the cursor.
To store the pixel vales I thought of using a 2D array with x,y coordinates of each pixel, the problem is that I run out of memory if I try to create an array with more than 200 rows. To store the value of any single pixel I would need 128x64 rows.
You have accidently hit upon one of the biggest constraints with the arduboy. You could store the pixel values of an array use single bits, but honestly that would still use a TON of your available memory. There are other ways to compress the data even more but they would be pretty complicated and would vary in efficiency as you draw.
But don’t forget to avoid calling arduboy.clear() or it will erase anything that’s been drawn.
With games that’s usually what you want, but for a drawing program it isn’t what you want to do.
Also please remember to use .ino or .cpp rather than .c.
The Arduboy2 object is a C++ class, you can’t access it from C code.
If you’re using the Arduino IDE to compile your code then your main code file needs to be a .ino file.
(If you’re using PlatformIO then you don’t need an .ino.)
If you use this technique and want to show a cursor, you’ll have to:
Save (at least) the contents of the screen screen buffer area that your cursor will occupy, to another variable (array or otherwise) in RAM.
Draw the cursor.
If a pixel is to change at the cursor, change it but also save info that will tell what colour the pixel has changed to.
Before moving the cursor:
Restore the saved area back to the screen buffer.
If a pixel was changed, set it to the saved colour.
Repeat all the steps whenever the cursor location is changed.
Keep in mind that drawing functions only change the contents of the RAM screen buffer. To actually see the changes, you have to call arduboy.display() where appropriate. Alternatively, you can continually call arduboy.display() once at the end of each frame, whether a change has been made or not.
Thanks all for your advices.
I still do not understand a couple of things:
if I use arduboy.drawPixel() I still need to store somehow all the coordinates of painted pixels to render them after I clear screen
I want the user to paint moving the cursor and clicking a button. If I avoid using arduboy.clear() the screen will get painted even if users doesn’t click the button. @MLXXXp are you suggesting to leave the screen painted (avoiding arduboy.clear) and subtract the cursor data everytime the user moves the arrows? Can I do it without clearing the screen?
If you use arduboy.drawPixel() and dont clear the screen you wont need to store all the co-ordinates because you are drawing directly. You would need to write your own code to display and change the pixels for the cursor though.
That’s why @Pharap said not to clear the screen, so you don’t loose the settings of all the pixels in the screen buffer.
Yes, that’s what the steps I posted instruct you to do.
Don’t subtract the cursor data. Save the pixel data in the buffer for the area where you want to place the cursor, then draw the cursor in that area. Restore that saved data to “erase” the cursor before repeating the steps to “move” the cursor to a new location.
You will need to write your own code to handle the cursor.
So when you move the cursor you will go through a few steps.
1)write the stored pixels that were under the cursor (this will erase the cursor)
2)store the pixels the cursor will cover when it moves
3)write the pixels to draw the cursor.
When you press a button to draw a pixel you need to make sure that that pixel is changed both on screen AND in the stored pixels, so when you move your cursor and the old data is restored, your change is saved.
Thats about as clear as I can make it without examples and there are people much better than me for that.
To anticipate the next question: How do I save the cursor area?
This method wastes a lot of RAM, because it stores only one pixel per byte, but it doesn’t require manipulating individual bits to store each pixel. For a cursor that occupies an 8 x 8 square of pixels this will use 64 bytes of RAM for saving. If you end up short on RAM, pixels could be stored in individual bits, at the expense of a larger and slower program. You could also directly access the screen buffer and save the area bytes at a time but this requires knowledge of the screen buffer layout and isn’t as portable.
constexpr int cursorSize = 8; // assumes a square cursor area
// where the pixels in the cursor area are saved
bool cursorArea[cursorSize][cursorSize];
// x and y are the coordinates of the top left corner of the cursor area
void saveCursorArea(int x, int y) {
for (int i = 0; i < cursorSize; i++) {
for (int j = 0; j < cursorSize; j++) {
cursorArea[i][j] = arduboy.getPixel(x + i, y + j);
}
}
}
void restoreCursorArea(int x, int y) {
for (int i = 0; i < cursorSize; i++) {
for (int j = 0; j < cursorSize; j++) {
arduboy.drawPixel(x + i, y + j, cursorArea[i][j]);
}
}
}
I haven’t actually tested this code other than making sure it compiles without errors. There could be bugs.
Thanks very much!
I wasn’t expecting to get the code
Anyway I was thinking of starting with 1 pixel cursor to make things easier, storing cursor x and y position in a different var before moving the arrows should make the trick.
Being able to see the cursor in all situations requires some thought. If you make it all white, it will disappear in large white areas (and similarly for all black).
You could use all white but put a black boarder around it, like a mouse pointer does. This obscures more of the actual drawn pixels underneath.
You could make the cursor the inverse of the pixels it covers (exclusive “or”). The cursor may become hard to see if the drawn pixel pattern is complex.
You could flash the cursor. This is probably the best but the hardest to accomplish.