In a drawing app, which uses setContext as the main feature to draw to one main image, what would be the best way to undo changes? The function I have in place means each time the touch state begins I have to use image:copy() on the whole screen and insert it in to a table to be read later on, then when I undo I just set the main image to the stored one then set it to nil and collect garbage.
The problem with doing the above is if I tap the screen continuously it crashes because of a memory overload and sometimes crashes randomly (and more regularly if I have apps open from what I’ve seen). I was hoping someone had tackled this problem already, I tried just inserting the image in to a table then using tbl[imgindex]:copy() but without success. I can’t really think of a way of doing this without having to use image:copy() .
I had one idea which I haven’t tested yet which would be to make a image that stays in the memory that I can draw the screen to with setContext then use image:copy in the undo function but I haven’t fully thought it through. I know it would work with one undo step but I want about 7-10 steps which is what I have now, and by steps I mean how many times someone can go back using the undo function. Any ideas are more than welcome.
You could keep track of everything that has been drawn in order in a table. When undoing, remove the last entry, clear the image, and redraw everything from the table onto a new image. That way you don’t have to store all images, just the drawing operations.
But then I would have to store variables of points for pen lines and shapes etc which I did before and was too memory intensive when it gets too long, I didn’t cap the limit of drawn objects til they’re set in stone though, and this time I’ve taken a completely different approach
Just to help, might not be the best solution:
I had the same problem with my 2d mesh drawer. I had to save the whole mesh, which is not so heavy but long and memory overloading in the end. So i wondered ‘when do i really want an undo?’. Generally it is after a 'oops! Mistake! ’ so i dont need to save for a very long time, i just need to go back a little. So i implemented only 1 undo, which saves memory. But if i save afyer every action, not good: too long and not back enough… Fortunately i have many buttons in the menu and change quite often of submenu choice. So it have implemented the save when i hit a menu button: this is good enough for the ‘ooops!’ and i dont lose too much because i change the menu choice quite often. That really works good enough for me.
How about saving images to disc? If you do it after the user has ended a touch then they might not notice the dip in FPS.
(I do one level of undo in the Harmony drawing application by rendering the current draw to an “undo” image. Then when the next drawing action starts the undo image is rendered on to the background, thus “baking” it in place.)
Well I decided to go with the one undo, it’s the most efficient and makes more sense, thanks!
Just an idea, even though you’ve already chosen one undo, what about having a button to press when you want to save? Like a checkpoint button? When you press it, it saves the current image to the undo table, so the user can save before they try something big, in case if it goes horribly wrong. You could still clip the amounts of undo, too.
(I prefer more than one undo, but that’s just my opinion. A checkpoint button would be nice, so it doesn’t flood your backups, and you can go back to a big checkpoint easily.)
@SkyTheCoder for what you say i use the memory slots to save intermediate versions. The undo is needed for less predictable times.
I had that idea sky but I didn’t think to put it along side the undo button, I’ve got a save button to actually save the image to documents but a checkpoint / restore to checkpoint would be nice
@Luatee I tried playing around with full screen drawing, and I was able to save 9 full screen images for 9 undo’s without a problem. I was able to do even more saves, but I set the limit at 9. The save function was called anytime my finger was lifted from the screen. I limited it to the last 9 draws so I wouldn’t use up memory when I did a lot of quick draws. There didn’t seem to be a problem no matter how quick I did the draws to force a save. The undo’s worked OK too, no matter how fast I pressed the undo button. I’m using a 16gb iPad 1, so maybe the retina image size is causing problems for you. I used image:copy to save the image, and image:copy to undo it. I displayed one image and did the copy from that image for the save, and copy to that image for the undo. The images were saved in a table.
That’s what I have been doing but it caused crashes with vigorous finger tapping, but some people do that in a drawing app if they make patterns so I decided to go with the one undo