175 lines
6.8 KiB
Markdown
175 lines
6.8 KiB
Markdown
### Complex Polygon Filling: An Implementation {#Heading5}
|
|
|
|
Listing 40.1 just shown presents a function, **FillPolygon()**, that
|
|
fills polygons of all shapes. If **CONVEX\_FILL\_LINKED** is defined,
|
|
the fast convex fill code from Chapter 39 is linked in and used to draw
|
|
convex polygons. Otherwise, convex polygons are handled as if they were
|
|
complex. Nonconvex polygons are also handled as complex, although this
|
|
is not necessary, as discussed shortly.
|
|
|
|
Listing 40.1 is a faithful implementation of the complex polygon filling
|
|
approach just described, with separate functions corresponding to each
|
|
of the tasks, such as building the GET and X-sorting the AET. Listing
|
|
40.2 provides the actual drawing code used to fill spans, built on a
|
|
draw pixel routine that is the only hardware dependency anywhere in the
|
|
C code. Listing 40.3 is the header file for the polygon filling code;
|
|
note that it is an expanded version of the header file used by the fast
|
|
convex polygon fill code from Chapter 39. (They may have the same name
|
|
but are *not* the same file!) Listing 40.4 is a sample program that,
|
|
when linked to Listings 40.1 and 40.2, demonstrates drawing polygons of
|
|
various sorts.
|
|
|
|
**LISTING 40.2 L40-2.C**
|
|
|
|
/* Draws all pixels in the horizontal line segment passed in, from
|
|
(LeftX,Y) to (RightX,Y), in the specified color in mode 13h, the
|
|
VGA's 320x200 256-color mode. Both LeftX and RightX are drawn. No
|
|
drawing will take place if LeftX > RightX. */
|
|
|
|
#include <dos.h>
|
|
#include "polygon.h"
|
|
|
|
#define SCREEN_WIDTH 320
|
|
#define SCREEN_SEGMENT 0xA000
|
|
|
|
static void DrawPixel(int, int, int);
|
|
|
|
void DrawHorizontalLineSeg(Y, LeftX, RightX, Color) {
|
|
int X;
|
|
|
|
/* Draw each pixel in the horizontal line segment, starting with
|
|
the leftmost one */
|
|
for (X = LeftX; X <= RightX; X++)
|
|
DrawPixel(X, Y, Color);
|
|
}
|
|
|
|
/* Draws the pixel at (X, Y) in color Color in VGA mode 13h */
|
|
static void DrawPixel(int X, int Y, int Color) {
|
|
unsigned char far *ScreenPtr;
|
|
|
|
#ifdef __TURBOC__
|
|
ScreenPtr = MK_FP(SCREEN_SEGMENT, Y * SCREEN_WIDTH + X);
|
|
#else /* MSC 5.0 */
|
|
FP_SEG(ScreenPtr) = SCREEN_SEGMENT;
|
|
FP_OFF(ScreenPtr) = Y * SCREEN_WIDTH + X;
|
|
#endif
|
|
*ScreenPtr = (unsigned char) Color;
|
|
}
|
|
|
|
**LISTING 40.3 POLYGON.H**
|
|
|
|
/* POLYGON.H: Header file for polygon-filling code */
|
|
|
|
#define CONVEX 0
|
|
#define NONCONVEX 1
|
|
#define COMPLEX 2
|
|
|
|
/* Describes a single point (used for a single vertex) */
|
|
struct Point {
|
|
int X; /* X coordinate */
|
|
int Y; /* Y coordinate */
|
|
};
|
|
/* Describes a series of points (used to store a list of vertices that
|
|
describe a polygon; each vertex connects to the two adjacent
|
|
vertices; the last vertex is assumed to connect to the first) */
|
|
struct PointListHeader {
|
|
int Length; /* # of points */
|
|
struct Point * PointPtr; /* pointer to list of points */
|
|
};
|
|
/* Describes the beginning and ending X coordinates of a single
|
|
horizontal line (used only by fast polygon fill code) */
|
|
struct HLine {
|
|
int XStart; /* X coordinate of leftmost pixel in line */
|
|
int XEnd; /* X coordinate of rightmost pixel in line */
|
|
};
|
|
/* Describes a length-long series of horizontal lines, all assumed to
|
|
be on contiguous scan lines starting at YStart and proceeding
|
|
downward (used to describe a scan-converted polygon to the
|
|
low-level hardware-dependent drawing code) (used only by fast
|
|
polygon fill code). */
|
|
struct HLineList {
|
|
int Length; /* # of horizontal lines */
|
|
int YStart; /* Y coordinate of topmost line */
|
|
struct HLine * HLinePtr; /* pointer to list of horz lines */
|
|
};
|
|
|
|
**LISTING 40.4 L40-4.C**
|
|
|
|
/* Sample program to exercise the polygon-filling routines */
|
|
|
|
#include <conio.h>
|
|
#include <dos.h>
|
|
#include "polygon.h"
|
|
|
|
#define DRAW_POLYGON(PointList,Color,Shape,X,Y) \
|
|
Polygon.Length = sizeof(PointList)/sizeof(struct Point); \
|
|
Polygon.PointPtr = PointList; \
|
|
FillPolygon(&Polygon, Color, Shape, X, Y);
|
|
|
|
void main(void);
|
|
extern int FillPolygon(struct PointListHeader *, int, int, int, int);
|
|
|
|
void main() {
|
|
int i, j;
|
|
struct PointListHeader Polygon;
|
|
static struct Point Polygon1[] =
|
|
{{0,0},{100,150},{320,0},{0,200},{220,50},{320,200}};
|
|
static struct Point Polygon2[] =
|
|
{{0,0},{320,0},{320,200},{0,200},{0,0},{50,50},
|
|
{270,50},{270,150},{50,150},{50,50}};
|
|
static struct Point Polygon3[] =
|
|
{{0,0},{10,0},{105,185},{260,30},{15,150},{5,150},{5,140},
|
|
{260,5},{300,5},{300,15},{110,200},{100,200},{0,10}};
|
|
static struct Point Polygon4[] =
|
|
{{0,0},{30,-20},{30,0},{0,20},{-30,0},{-30,-20}};
|
|
static struct Point Triangle1[] = {{30,0},{15,20},{0,0}};
|
|
static struct Point Triangle2[] = {{30,20},{15,0},{0,20}};
|
|
static struct Point Triangle3[] = {{0,20},{20,10},{0,0}};
|
|
static struct Point Triangle4[] = {{20,20},{20,0},{0,10}};
|
|
union REGS regset;
|
|
|
|
/* Set the display to VGA mode 13h, 320x200 256-color mode */
|
|
regset.x.ax = 0x0013;
|
|
int86(0x10, ®set, ®set);
|
|
|
|
/* Draw three complex polygons */
|
|
DRAW_POLYGON(Polygon1, 15, COMPLEX, 0, 0);
|
|
getch(); /* wait for a keypress */
|
|
DRAW_POLYGON(Polygon2, 5, COMPLEX, 0, 0);
|
|
getch(); /* wait for a keypress */
|
|
DRAW_POLYGON(Polygon3, 3, COMPLEX, 0, 0);
|
|
getch(); /* wait for a keypress */
|
|
|
|
/* Draw some adjacent nonconvex polygons */
|
|
for (i=0; i<5; i++) {
|
|
for (j=0; j<8; j++) {
|
|
DRAW_POLYGON(Polygon4, 16+i*8+j, NONCONVEX, 40+(i*60),
|
|
30+(j*20));
|
|
}
|
|
}
|
|
getch(); /* wait for a keypress */
|
|
|
|
/* Draw adjacent triangles across the screen */
|
|
for (j=0; j<=80; j+=20) {
|
|
for (i=0; i<290; i += 30) {
|
|
DRAW_POLYGON(Triangle1, 2, CONVEX, i, j);
|
|
DRAW_POLYGON(Triangle2, 4, CONVEX, i+15, j);
|
|
}
|
|
}
|
|
for (j=100; j<=170; j+=20) {
|
|
/* Do a row of pointing-right triangles */
|
|
for (i=0; i<290; i += 20) {
|
|
DRAW_POLYGON(Triangle3, 40, CONVEX, i, j);
|
|
}
|
|
/* Do a row of pointing-left triangles halfway between one row
|
|
of pointing-right triangles and the next, to fit between */
|
|
for (i=0; i<290; i += 20) {
|
|
DRAW_POLYGON(Triangle4, 1, CONVEX, i, j+10);
|
|
}
|
|
}
|
|
getch(); /* wait for a keypress */
|
|
|
|
/* Return to text mode and exit */
|
|
regset.x.ax = 0x0003;
|
|
int86(0x10, ®set, ®set);
|
|
}
|