93 lines
5.1 KiB
Markdown
93 lines
5.1 KiB
Markdown
------------------------ --------------------------------- --------------------
|
||
[Previous](38-03.html) [Table of Contents](index.html) [Next](39-01.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
Listing 38.2 isn’t particularly interesting; it merely draws each
|
||
horizontal line in the passed-in list in the simplest possible way, one
|
||
pixel at a time. (No, that doesn’t make the pixel the fundamental
|
||
primitive; in the next chapter I’ll replace Listing 38.2 with a much
|
||
faster version that doesn’t bother with individual pixels at all.)
|
||
|
||
Listing 38.1 is where the action is in this chapter. Our goal is to scan
|
||
out the left and right edges of each polygon so that all points inside
|
||
and no points outside the polygon are drawn, and so that all points
|
||
located exactly on the boundary are drawn only if they are not on right
|
||
or bottom edges. That’s precisely what Listing 38.1 does. Here’s how:
|
||
|
||
Listing 38.1 first finds the top and bottom of the polygon, then works
|
||
out from the top point to find the two ends of the top edge. If the ends
|
||
are at different locations, the top is flat, which has two implications.
|
||
First, it’s easy to find the starting vertices and directions through
|
||
the vertex list for the left and right edges. (To scan-convert them
|
||
properly, we must first determine which edge is which.) Second, the top
|
||
scan line of the polygon should be drawn without the rightmost pixel,
|
||
because only the rightmost pixel of the horizontal edge that makes up
|
||
the top scan line is part of a right edge.
|
||
|
||
If, on the other hand, the ends of the top edge are at the same
|
||
location, the top is pointed. In that case, the top scan line of the
|
||
polygon isn’t drawn; it’s part of the right-edge line that starts at the
|
||
top vertex. (It’s part of a left-edge line, too, but the right edge
|
||
overrides.) When the top isn’t flat, it’s more difficult to tell in
|
||
which direction through the vertex list the right and left edges go,
|
||
because both edges start at the top vertex. The solution is to compare
|
||
the slopes from the top vertex to the ends of the two lines coming out
|
||
of it in order to see which is leftmost. The calculations in Listing
|
||
38.1 involving the various deltas do this, using a rearranged form of
|
||
the slope-based equation:
|
||
|
||
(DeltaYN/DeltaXN)>(DeltaYP/DeltaXP)
|
||
|
||
Once we know where the left edge starts in the vertex list, we can
|
||
scan-convert it a line segment at a time until the bottom vertex is
|
||
reached. Each point is stored as the starting X coordinate for the
|
||
corresponding scan line in the list we’ll pass to
|
||
**DrawHorizontalLineList**. The nearest X coordinate on each scan line
|
||
that’s on or to the right of the left edge is selected. The last point
|
||
of each line segment making up the left edge isn’t scan-converted,
|
||
producing two desirable effects. First, it avoids drawing each vertex
|
||
twice; two lines come into every vertex, but we want to scan-convert
|
||
each vertex only once. Second, not scan-converting the last point of
|
||
each line causes the bottom scan line of the polygon not to be drawn, as
|
||
required by our rules. The first scan line of the polygon is also
|
||
skipped if the top isn’t flat.
|
||
|
||
Now we need to scan-convert the right edge into the ending X coordinate
|
||
fields of the line list. This is performed in the same manner as for the
|
||
left edge, except that every line in the right edge is moved one pixel
|
||
to the left before being scan-converted. Why? We want the nearest point
|
||
to the left of but not on the right edge, so that the right edge itself
|
||
isn’t drawn. As it happens, drawing the nearest point on or to the right
|
||
of a line moved one pixel to the left is exactly the same as drawing the
|
||
nearest point to the left of but not on that line in its original
|
||
location. Sketch it out and you’ll see what I mean.
|
||
|
||
Once the two edges are scan-converted, the whole line list is passed to
|
||
**DrawHorizontalLineList**, and the polygon is drawn.
|
||
|
||
Finis.
|
||
|
||
### Oddball Cases {#Heading7}
|
||
|
||
Listing 38.1 handles zero-length segments (multiple vertices at the same
|
||
location) by ignoring them, which will be useful down the road because
|
||
scaled-down polygons can end up with nearby vertices moved to the same
|
||
location. Horizontal line segments are fine anywhere in a polygon, too.
|
||
Basically, Listing 38.1 scan-converts between active edges (the edges
|
||
that define the extent of the polygon on each scan line) and both
|
||
horizontal and zero-length lines are non-active; neither advances to
|
||
another scan line, so they don’t affect the edges being scanned.
|
||
|
||
I’ve limited this chapter’s code to merely demonstrating the principles
|
||
of filling convex polygons, and the listings given are by no means fast.
|
||
In the next chapter, we’ll spice things up by eliminating the floating
|
||
point calculations and pixel-at-a-time drawing and tossing a little
|
||
assembly language into the mix.
|
||
|
||
------------------------ --------------------------------- --------------------
|
||
[Previous](38-03.html) [Table of Contents](index.html) [Next](39-01.html)
|
||
------------------------ --------------------------------- --------------------
|
||
|
||
* * * * *
|
||
|
||
Graphics Programming Black Book © 2001 Michael Abrash
|