#109052 - philip - Tue Nov 14, 2006 3:58 pm
I?ve been trying to write a little paint package in which I can paint with a brush with a relatively wide radius (about 8 pixels). My drawing function is passed the start and end points for the line (these points are sampled every frame from the stylus position, so there would be gaps in the line if we just drew the points at every frame), and draws a line between the two points using circles. That is, we draw circles at intervals along the line from start to finish.
The problem is, in order to ensure a relatively unbroken line, I need to draw the circles every two pixels or so. This leads to a lot of overdraw! I use this approach because I also want to mix the colour I?m currently drawing with the colour I?m drawing onto. Drawing circles allows me to change the colour of the brush at each step.
My question is, is there a more intelligent way to draw a thick line like this which reduces overdraw? Also, does anybody know a good way I can mix the current colour with what I?m drawing on to, so my pen gradually changes colour? This does not lend itself to using transparency, since I actually need the pen to change colour as I move over a new colour. Essentially, I need to be able to mix-up the colours on screen.
I haven?t had much luck finding any examples of doing any of this, so any help would be appreciated. I have looked at DS-Paint. There?s no source for it, but it?s interesting that it doesn?t seem to be limited to reading the pen every frame, because there?s no hint of the lines breaking up into straight lines. I?m pretty new to DS programming, so can somebody tell me how frequently I can read the touch screen?
#109053 - Mighty Max - Tue Nov 14, 2006 4:15 pm
philip wrote: |
My question is, is there a more intelligent way to draw a thick line like this which reduces overdraw? |
Draw a half circle around each points center in the radius of the line's thickness. (from linedirection+90 till linedirection+270 degrees)
From the starting and ending points from these half circles draw a 1 pt line (bresenham or other fast algos) to the corresponding end of the other side.
You can use a fastfill on the now enclosed space (might get to some trouble) or create the half-circles filled and move the starting points of both of the lines 1 pixel per step into the circles middle and draw a line between.
This way there shouldnt be an overdraw.
(+ drawing multiple lines is most likely faster the drawing multiple circles, as trigonometric functions are evil, and shouldnt be encapsuled in loops where other ways are possible)
_________________
GBAMP Multiboot
#109056 - philip - Tue Nov 14, 2006 4:52 pm
Mighty Max wrote: |
You can use a fastfill on the now enclosed space (might get to some trouble) or create the half-circles filled and move the starting points of both of the lines 1 pixel per step into the circles middle and draw a line between. |
Using multiple lines, you could get a few pixels which don't get drawn, couldn't you? I'd have to interpolate colour across the lines, too. Because of this, I probably wouldn't be able to use your other suggestion of a fast fill.
Mighty Max wrote: |
(+ drawing multiple lines is most likely faster the drawing multiple circles, as trigonometric functions are evil, and shouldnt be encapsuled in loops where other ways are possible) |
Um, drawing circles doesn't require any trig functions...
#109132 - philip - Wed Nov 15, 2006 10:39 am
Nobody else got any ideas, then? Oh well...
Can anybody give me a snippet of code that DMA copies a given, single value to a specified starting point and size? All the code I've found copies one area to another, but I just need to fill with a certain value to do fast-filling with a fixed colour.
#109154 - outphase - Wed Nov 15, 2006 5:46 pm
I recently asked a similar question. Mine was just a pen stroke 1 pixel big. In order to create a continuous line, you have to draw a line between your 2 sampled points. I used the Bresenham line drawing algorithm to do it.
#109159 - Sausage Boy - Wed Nov 15, 2006 5:59 pm
What you want to do is draw a rectangle between the two points, with half circles on the sides.
_________________
"no offense, but this is the gayest game ever"
#109160 - philip - Wed Nov 15, 2006 6:06 pm
Sausage Boy wrote: |
What you want to do is draw a rectangle between the two points, with half circles on the sides. |
Can anybody point me at a source for a filled rectangle algorithm? I haven't had much luck finding one. Filling with a gradient would be good, too.
#109162 - Mighty Max - Wed Nov 15, 2006 6:23 pm
philip wrote: |
Mighty Max wrote: |
You can use a fastfill on the now enclosed space (might get to some trouble) or create the half-circles filled and move the starting points of both of the lines 1 pixel per step into the circles middle and draw a line between. |
Using multiple lines, you could get a few pixels which don't get drawn, couldn't you? I'd have to interpolate colour across the lines, too. Because of this, I probably wouldn't be able to use your other suggestion of a fast fill.
|
Thats why i spoke from troubles. Wouldnt happen when drawing apt lines from the out to the inside. Color interpolating is very possible this way. Bresenham is pretty easy to be enhanced for color mixing. Or applying stamps on it.
Quote: |
Mighty Max wrote: |
(+ drawing multiple lines is most likely faster the drawing multiple circles, as trigonometric functions are evil, and shouldnt be encapsuled in loops where other ways are possible) |
Um, drawing circles doesn't require any trig functions... |
There are some workarounds, but they aren't much better tbh.
If you find a way to draw a circle (with n pixel sets) that is faster then drawing a linear line with the same amount (n) of pixels to change, i would be more then interested in hearing it. None of the workarounds to trig in circles i know even comes near to that. And uggly are they all ;) one is O(n^2) where others have visible deformations (i.e. nearing with p2(x))
_________________
GBAMP Multiboot
#109168 - tepples - Wed Nov 15, 2006 7:08 pm
Frankly, big memory fills are faster in software (stmia loop) than in hardware.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#109173 - DekuTree64 - Wed Nov 15, 2006 8:43 pm
Since the pen will probably be pretty small, circle drawing could just be a matter of stamping a bitmap onto the canvas.
For the rectangle filling part of drawing a thick line, I'd just go with standard scan conversion. Check out this article for some info.
For the capping of the rectangle, place the center of your circle stamp at the end of the line, and then trace the edge of the rectangle again as you draw it, and don't draw the half that would overlap the rectangle.
For the blending tool, I probably would just go with repetitive circle drawing. Maybe keep a paintbrush image in RAM, load the pixels from the canvas at the 'old' pen position into the brush, and then stamp the brush onto the canvas at the 'new' pen position, at some user-defined alpha level.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku
#109252 - philip - Thu Nov 16, 2006 11:40 am
DekuTree64 wrote: |
For the rectangle filling part of drawing a thick line, I'd just go with standard scan conversion. Check out this article for some info.
|
Thanks, that's what I needed.
DekuTree64 wrote: |
For the blending tool, I probably would just go with repetitive circle drawing. Maybe keep a paintbrush image in RAM, load the pixels from the canvas at the 'old' pen position into the brush, and then stamp the brush onto the canvas at the 'new' pen position, at some user-defined alpha level. |
What I'm doing right now is a simplified version of this. I pick up a solid colour from where I first touch, and as I drag around, I find the average colour of the area I'm dragging over. I find the difference between the current brush colour and the new area's colour, and change the current colour by a small fraction of this value. Weird thing is, is that a darker colour always seems to be dominant and easily ends up smothering a lighter colour, while a light colour being mixed into a dark one tends to disappear quickly. It's a bit odd!
#109270 - DekuTree64 - Thu Nov 16, 2006 6:25 pm
philip wrote: |
Weird thing is, is that a darker colour always seems to be dominant and easily ends up smothering a lighter colour, while a light colour being mixed into a dark one tends to disappear quickly. |
Probably rounding error since each color channel is only 5 bits. Try bumping up the accuracy on your internal brush image to 16 bits per channel or something, and shift it down when drawing it to the canvas.
The canvas itself may still cause trouble though, but increasing the accuracy there could get complicated, not to mention memory-hungry.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku