Filling a polygon is the process of taking the information created by the scan converter, and using it to fill the polygon using horizontal strips of pixels. This is also known as Rendering.
This is usually one of the most time consuming pieces of code, especially if you are trying to perform bump-mapping and phong shading and texture mapping all in one go. So it is well worth spending time optimising this inner loop carefully. It will be quite justified by the speed increase.
Flat shading simply means filling the whole of the polygon in the same colour. It is a very easy piece of code to write, especially on an 8-bit screen, and can be made to run four times faster in Mode-X.
Firstly a very simple algorithm:
minY = (Top of polygon)
maxY = (Bottom of polygon)
loop Y from minY to maxY
x1 = left(Y)
x2 = right(Y)
loop X from x1 to x2
plot a pixel at (X,Y)
end of X loopend of Y loop
Never use this algorithm. It is just about the slowest way of acheiving a flat fill. Everything
about the inner loop is wrong. Let's take it apart bit by bit:1. The plot pixel routine is called for every pixel on the polygon. This represents hundreds or thousands of unnecessary procedure calls. Moving the pixel plotting code into the inner loop will eradicate these.
2. The plot pixel routine will calculate the address of each pixel you ask it to plot. This usually involvesa multiply somewhere along the line. Again waste of time. For a start you know that, inside the inner loop, every pixel you plot is right next to the previous one. So you only need calculate the address of the first pixel, and the subsequent pixels along that line are at the next address:
minY = (Top of polygon)
maxY = (Bottom of polygon)
loop Y from minY to maxY
x1 = left(Y)
x2 = right(Y)
PixelAddress = address of pixel at (x1, Y)
loop X from x1 to x2
write a byte to (PixelAddress)
PixelAddress = PixelAddress + 1
end of X loopend of Y loop
Much faster already.3. Most computers are capable or writing not only bytes, but also words and double words. Writing one of these is as fast as writing a byte (as long as it is aligned correctly). So you can fill the line in half the time. You must be sure however that words are aligned on even addresses, and double words arealigned on addresses divisible by 4:
(I do not apologise for using GOTO's, they make it much easier to convert pseudocode into assembler)
minY = (Top of polygon)
maxY = (Bottom of polygon)
loop Y from minY to maxY
x1 = left(Y)
x2 = right(Y)
length = x2-x1+1 ; number of pixels to write
PixelAddress = address of pixel at (x1, Y) ; calculate address of first pixel
if length = 1 then ; if there is only one pixel to draw
write a byte to (PixelAddress) ; then write one pixel
goto DoneThisLine ; and finish
end if
if (PixelAddress AND 3) =1 or 3 ; if it's not on a word or doubleword boundary
write a byte to (PixelAddress) ; then write one pixel
length = length - 1 ;
PixelAddress = PixelAddress + 1 ; next address
end if
if length <= 2 then goto LastStuff ; if there are only a couple of pixels left, then don't
; bother being flash, just write them
if (PixelAddress AND 3) =2 ; if it's on a word boundary
write a word to (PixelAddress) ; then write 2 pixels
length = length - 2
PixelAddress = PixelAddress + 2 ; next address
end if
if length < 4 then goto LastStuff ; if there are only a couple of pixels left, then don't
; bother being flash, just write them
loop while length >= 4 ; MAIN INNER LOOP
write a DoubleWord to (PixelAddress) ; write 4 pixels
PixelAddress = PixelAddress + 4 ; next address
length = length - 4 ; end of loop
; END OF LOOP
LastStuff: ; now write the last couple of pixels
if length = 3 then ; if there are 3 pixels left
write a word to (PixelAddress) ; then draw 2 pixels
write a byte to (PixelAddress+1) ; and 1 more
goto DoneThisLine ; and finish
end if
if length = 2 then ; if there are 2 pixels left
write a word to (PixelAddress) ; then draw them
goto DoneThisLine ; and finish
end if
if length = 1 then ; if there's one pixel left
write a byte to (PixelAddress+1) ; then draw it
goto DoneThisLine ; and finish
end if
DoneThisLine: ; FINISHED THIS LINE
end of Y loop