Not quite yet...
Sorry, had to :D
Gory details:
Making these was about as close to "by hand" as you could get without actually drawing it yourself. I leave the heavy lifting to premade solutions and sort of dangle them together. I start by finding an image, cropping and resizing to a size that will fit (about 245x165). Convert to a black-and-white-pixel-only bitmap (this step usually took a bit of tweaking to get a decent final image). This first part is all done "by hand", but finally I run the image through a script that converts it into a monster string of 1's and 0's. And double finally, I run that string through another script that paints the picture, pixel by pixel. (And yes, the scripts are in two different languages :S I'm lazy.)
It's not optimized for speed at all; the Sistine chapel one would take 1 hour and 45 minutes in real time. Thank goodness for turbo :) It could be made much, much faster I bet, but I just stuck with what worked.
The next step is to try true color. Initially I'm planning on reducing the 15 available colors to RGB values, then look at the incoming picture's RGB values and finding the closest match arithmetically. A better solution would be to try to create colors by making patterns from the preset colors, for example blue speckled with black to make a dark blue, but that seems like it would take quite a bit more effort.
Joined: 1/16/2008
Posts: 358
Location: The Netherlands
words can't describe my level of surprise and appreciation :D really great idea (and props for working it out like you did!)
any next steps planned? (though this is already *amazing*!)
A nice thing would be converting SVGs into Mario Paint 'movies'. Seeing as SVG is a vector graphics format, it should be much easier than trying to interpret arbitrary raster data as the clearly vector commands available in the program.
Also, if your program doesn't do it already, it should probably draw boustrophedon for speed. Well done. :)
Programs like imagemagick can take a user-defined color palette and then color-reduce + dither an image using that palette. It should be fairly easy to automatize, given that Mario Paint uses a fixed palette (AFAIK).
Those look superb. The creation of those images (sped up if necessary) would make great youtube videos.
Anything for you sticky :)
Glad folks enjoyed these, thank you for your kind words.
Indeed, especially the color ones. It paints one color at a time so it's fun seeing random blobs turn into recognizable images. At this time, they would need to sped up a lot though; I recorded the drawing of Kirby and it takes over 2 hours in real time :O Speaking of which...
Yes, I thought about that. I've always liked the image of "as the ox plows the field". Right now it doesn't for simplicity's sake.
That would be awesome, and the file format looks nice (well if you don't hate XML. Which I don't... yet.)
That's pretty much how I did the color ones, albeit by hand. Mario Paint does have a standard palette of 15 colors (perhaps more in predefined stamps, I haven't checked). I created a custom palette of those colors and let my imaging software go to town. After that it was pretty much the same as the B/W ones, but with more colors. scolorq looks great, however from the page it looks like it does not support custom palettes as of yet... unless I missed something. Any other suggestions for good palette reducing? I'm on Windows XP btw :S
Hmm, you're right. If you've got a fixed palette, then it's just the matter of selecting the best dithering algorithm. http://en.wikipedia.org/wiki/Dither#Dithering_algorithms
My recommendation is to use little to no dithering, e.g. ordered dithering with 2x2 pattern at most. This would also enable you to use the predefined dithering patterns in Mario Paint to speed up the painting.
I did some testing with Imagemagick and Scolorq (these were not captured from Mario Paint):
Image 1: Image with Mario Paint palette, no dithering
Image 2: Image with Mario Paint palette, hilbert-peano dithering
Image 3: Image with Mario Paint palette, o2x2 dithering
Image 4: Image with Mario Paint palette, o2x1 dithering
Image 1: Image with Scolorq custom palette and default dithering, one would naturally change the colors to closest approximates in Mario Paint
Image 2: Image with imagemagick custom palette and o2x1 dithering, ―"―
Image 3: Image with imagemagick custom palette and o2x2 dithering, ―"―
Image 1: I think imagemagick's ordered dithering algorithm is broken somehow. I wrote a custom program. This image has a 2x1 dithering pattern and Mario Paint palette.
Image 2: The same, but color comparisons done in YUV colorspace.
Mario Paint palette for reference:
A few more:
Re: Adjusting the images, I suppose a neural network program could be developed to adjust the image's colour curves (i.e. saturation, lightness, contrast and hue) to optimize it to best fit to Mario Paint palette with or without 2x1 dithering patterns.
Actually I prefer the first image you listed. :) I think dithering looks very ugly.
Edit: Well, except for the fairy, she doesn't look great there. Hrm.
To utilize the paint/floodfill tool effectively, you should first run an edge detection filter to the image (basically, plot everywhere where neighbouring colors differ), then draw the sections indicated in that image (using the image's intended colors, of course), and then floodfill everything that was missing.
When you detect the edges, you should probably ignore the individual pixels in dithering patterns and concentrate on the perceived color.
For gradients, there's no other way than to plot the dithering patterns manually (hopefully utilizing the predefined dithering brushes where possible).
Using the copy&paste tool would be neat, but I don't think there are many places in most images where that would work.
For generating a natural looking method of drawing the edges you could apply a floodfill style algorithm. Just follow the edges in the direction that is in the same color and has the least angular change, and when you hit a dead end (a point that has no surrounding pixels that are yet to be traced), choose another yet unprocessed intersection / edge (preferably one that is closest to where you stopped) and repeat, until you have traced all the edges. When choosing another point to trace, try to choose one in the same color; and if none are remaining, then choose a different color.
When drawing the edges, estimate the width of the brush needed, and draw on the center of the edge. If the brush is wider than needed at some point, keep drawing; you can later come back and tidy the overdrawn portions. Keep track of what you have drawn by simulating the algorithm on a virtual canvas, so you can see what still needs to be done. Just be careful that you don't create an infinite loop by overdrawing on two overlapping locations in turns.
For the floodfill, you should research on the algorithm used by the game to perform the floodfill, and choose a floodfill point that is fastest by the game to perform. If there are no differences, then choose the point by artistic concerns.
To find the end of lines, you could use a an algorithm that checks each remaining pixel of the image and plots a virtual line to each eight cardinal directions along that line, and chooses the pixel where the average length of those lines is the shortest. To avoid embarrassing misestimations at jittered edges, you should probably do so for every the 5-pixel star shaped groups.
Bisqwit: Thanks for the dithering info and many wise words on optimization. It'll be fun to see what can be done.
LagDotCom: Yes, two of my favorite ones are Mario and the soup can, and those are dither free. Of course, the source images just happen to use colors very similar to the fixed palette. Fancy that, it's easy to paint Mario in Mario Paint :)
I like this one, too, which is also dither free:
A few more for good measure. The top Roy Lichtenstein seemed like a good candidate as it had few colors, but took a lot of tweaking just to get this far.
I think the last one is really cool. It helps that I like the Simpsons AND Abbey Road... but it also converted well.
I don't get it. How do you even draw pixel by pixel in Mario Paint? All tools I have tried have at least 2x2 pixels footprint on the canvas.
Or is it that there isn't any choice, and you must thin the lines by overlapping them with different color lines?
EDIT: Ah, figured it out. Use the "special stamp" feature to create some handy brushes for the movie.
Yeah, stamps for the win. I guess if you could remove a couple more colors (trivial for some images, not so much for others) you could potentially make other usefully shaped stamps, though I can't think of what off hand.
So are you making a better script Mr. Bisqwit? I'll post my code later today probably. It's pretty ugly right now though :S
I'm partial to the Mandelbrot set pictures myself :) Also some of the dithering on the color wheels is very impressive, I did a couple tests on a similar image (from the scolorq site you linked to) and they looked like crap compared to those
I'm using a hack that allows joypad input by the way... If you could get the actual mouse working that would be a huge time saver right there as I assume you could move arbitrarily fast between points on the screen.
Alden, very nice! I'm pro-Waluigi as well so that makes it even better. The Abbey Road Simpsons is great too(guess I must've missed that episode). Nice choices for drawing; I look forward to your further work on this.
I just read about the SNES mouse protocol. Seems pretty screwed up to me, too
Bisqwit, I found some code that might help you. Here's something general about the protocol and this file includes a snesmouse.c and .h for querying the mouse and reading its input. Might also be used to emulate one for an emulator?
Yeah. The problem is that there is no correspondance between the emulator's knowledge of mouse cursor's position and the actual position in the game.
The movie file describes an absolute position of the mouse cursor. When you make a movie, this position is clamped to the range 0..255 horizontally and 0..239 vertically, assumed to represent the entire screen. But this is not what the console gives the game. The console gives the game delta values, and the game is free to interpret those values as it pleases. snes9x calculates the delta by comparing the previous and current mouse positions.
The consequences of this design is that if your cursor is at (220,220) (as snes9x thinks) but in fact, in the game it is at (220,150), and you attempt to move the cursor down, when snes9x thinks your cursor is at (220,239), you no longer can go down, even if the game cursor is only at (220,180). If you try to go further down, the mouse escapes the snes9x window. In order to get the game's mouse cursor further below, you will have to move the cursor up very quick (jump immediately to snes9x coordinates (220,80) for example), which will cause the game to ignore the movement: the game's cursor stays at (220,180) or somewhere nearby. Now you can move it further down.
This problem makes mouse-using movies practically impossible to create "normally".
In the movie file this problem is mitigated by the fact that the 0..239 clamping does not happen. Instead, it is clamped to -32768..32767 range. (Hope your best that this range is sufficient!) This enables you to roam the cursor freely.
However, the problem is knowing where the cursor is:
When you feed the game a delta of 1, it is safe to assume that the cursor moves by 1 pixel. However, when you feed a delta of 20, the cursor might move by 15 pixels, or 40 pixels, or 0 pixels, depending on how it is programmed. This makes it very difficult to predict where your cursor is, and more importantly, to predict what kind of input you need to generate to place the cursor in some specific location.
In Mario Paint, I did some testing, and I found the following
-- If you move the cursor vertically more than 1 pixel per frame, a slight vertical desynchronization will happen and very soon the cursor is not where you think it is.
-- You can move the cursor horizontally as fast as you like -- well, almost. Moving more than ~80 pixels per frame will cause the game to ignore your input, but otherwise, it's desync free.
-- Unless the game is busy. Mouse events, including movements, are ignored when the game is busy. Such as after setting a pixel, or after clicking an icon.
-- Clicking something for 1 frame does not register. Clicking for 2 frames usually is enough.
-- Occasionally the game forces your cursor to some position on screen. For example, when you click "save" on the custom cursor editor. Your input generator must be aware of this fact, or you'll experience a desync.
Oh, I was using memory address 7E0226 and 7E0227 to track where the game thinks the cursor is... I take it you're using a script to generate a movie file whereas I'm using snes9x+Lua to control the game directly. And it doesn't seem to control the mouse, hence the joypad hack.
Well, that seems like quite a challenge :) I have faith in you though.
Moving the mario paint mouse cursor programmatically (with lua) seems like a nightmare. However, how is it moved in snes9x when playing normally? Does snes9x support mouse input, or does it emulate it some other way? How does this work with frame advance?
I was thinking: How hard would it be to hack snes9x to overlay a semi-transparent image (read from an image file) over the emulator window? Could this even be done currently with lua? (I really don't know what lua in snes9x can do.)
Doing this would allow for a human to make a TAS of mario paint to create one of those cool colored images. The human would simply have to replicate the overlaid image in mario paint. Naturally he can try to do it as optimally (ie. fast) as possible, by using all the tools available in mario paint (such as floodfilling, etc).