If I understand this correctly, this is talking about rerendering a single scanline's worth of bitmap in the horizontal blanking period. Lines that are more horizontal than vertical would take longer during that blank, simply because there are more pixels to render for that scanline, whereas a more vertical line would generally only have to draw 1 pixel per scanline. The overall length of the line doesn't matter, you'd be bounded by the dx/dy ratios being large per scanline that the line drawing is active.
The state that you'd have to maintain per active line isn't just the x0,y0,x1,y1 coords, but also includes sx or sy, and err in the algorithm you listed.
For those that don't understand Bresenham, consider a typical line drawing algorithm first:
- Start at x0, y0.
- Calculate dx and dy.
- If dy > dx, you're a more vertical line, else you're a more horizontal line.
- Vertical: Loop over y0->y1, at each step calculate x0 += dx/dy, plot pixel at (x0,y0).
- Horizontal: Loop over x0->x1, at each step calculate y0 += dy/dx, plot pixel at (x0,y0).
Now, this requires division with a fixed (or floating) point result. What Bresenham does is skip the division step, and considers the numerator & denominator separately to keep everything as integers.
Let's take the vertical-line approach, as that's the direction of the raster scan.
- Precalculate sx = the sign of dx, either -1 or +1.
- Loop over y0->y1
- Instead of x0 += dx/dy, track both x0 and a separate numerator (called "err" in the posted algo)
- num += dx.
- If num >= dy, then our fractional component is finally greater than 1, so carry the fractional surplus over to our main x0.
- num -= dy (the denominator)
- x0 += sx
Both Bresenham and fixed-point methods use separate loops for lines that are more horizontal or more vertical, and some even use up to 8 different loops for the 4 cardinal directions simplified, and then the 4 angular quadrants. But in general, you want to swap coordinates and use absolute values in there to just deal with distances and not directions as much as possible.
A way to get around this is to make the 'if' step in the above list a 'while' loop. This means that while vertically traversing a screen, you could draw more than 1 pixel for more horizontal lines, the worst case being a ton of purely horizontal lines that span the screen and all overlap in the same scanline. You also need to make sure that this iteration stops once x1 is reached, so you don't overshoot your intended endpoint while accumulating a potentially large dx/dy.
So, Bresenham requires more intermediate state variables per line, and is an add, test, conditional add & sub per step.
Fixed point, on the other hand, could precalculate all its dx/dy deltas during vblank. Then each step is just x0 += dx, and the fixed-point addition easily tracks both the integer & fractional portions of the coordinate. However, the variables do need to be twice as long to carry the required precision.
In order to draw horizontal lines, you'd need to remember both x0 and the new x0'=x0+dx.
- If x0' is still the same as x0, then just draw the 1 pixel. This is a vertical portion of the line.
- If x0' changed, then draw all the pixels between x0 and x0', not including x0.
As I'm not a hardware guy, I don't know which loop would be cheaper/faster in hardware to implement, but these are the very basic steps between the two options.
(Note also that in order to draw lines well-balanced, you need to start off with a half-pixel offset fudge:
Code: Select all
0######### Going from pixel-corner to pixel-corner, no fudge
#1
0##### Going from pixel-center to pixel-center, with a half-pixel vertical fudge
#####1
In Bresenham, this means the numerator starts off with half the appropriate delta instead of at zero; in fixed point this means your starting coordinate gets a +0.5 offset, so that it overflows sooner.
Also, if you want smooth motion for 3d type stuff, you really want sub-pixel precision coordinates for the endpoints given to the renderer, which will certainly demand fixed point and not work well with Bresenham.)