g4tools
5.4.0
g4tools
tools
zb
line
Go to the documentation of this file.
1
// Copyright (C) 2010, Guy Barrand. All rights reserved.
2
// See the file tools.license for terms.
3
4
#ifndef tools_zb_line
5
#define tools_zb_line
6
7
/* from X/poly.h */
8
9
/*
10
* This file contains a few macros to help track
11
* the edge of a filled object. The object is assumed
12
* to be filled in scanline order, and thus the
13
* algorithm used is an extension of Bresenham's line
14
* drawing algorithm which assumes that y is always the
15
* major axis.
16
* Since these pieces of code are the same for any filled shape,
17
* it is more convenient to gather the library in one
18
* place, but since these pieces of code are also in
19
* the inner loops of output primitives, procedure call
20
* overhead is out of the question.
21
* See the author for a derivation if needed.
22
*/
23
24
25
/*
26
* In scan converting polygons, we want to choose those pixels
27
* which are inside the polygon. Thus, we add .5 to the starting
28
* x coordinate for both left and right edges. Now we choose the
29
* first pixel which is inside the pgon for the left edge and the
30
* first pixel which is outside the pgon for the right edge.
31
* Draw the left pixel, but not the right.
32
*
33
* How to add .5 to the starting x coordinate:
34
* If the edge is moving to the right, then subtract dy from the
35
* error term from the general form of the algorithm.
36
* If the edge is moving to the left, then add dy to the error term.
37
*
38
* The reason for the difference between edges moving to the left
39
* and edges moving to the right is simple: If an edge is moving
40
* to the right, then we want the algorithm to flip immediately.
41
* If it is moving to the left, then we don't want it to flip until
42
* we traverse an entire pixel.
43
*/
44
#define LARGE_COORDINATE 1000000
45
#define SMALL_COORDINATE -LARGE_COORDINATE
46
47
#define BRESINITPGON(dy, x1, x2, xStart, d, m, m1, incr1, incr2) { \
48
int dx;
/* local storage */
\
49
\
50
/* \
51
* if the edge is horizontal, then it is ignored \
52
* and assumed not to be processed. Otherwise, do this stuff. \
53
*/
\
54
if ((dy) != 0) { \
55
xStart = (x1); \
56
dx = (x2) - xStart; \
57
if (dx < 0) { \
58
m = dx / (dy); \
59
m1 = m - 1; \
60
incr1 = -2 * dx + 2 * (dy) * m1; \
61
incr2 = -2 * dx + 2 * (dy) * m; \
62
d = 2 * m * (dy) - 2 * dx - 2 * (dy); \
63
} else { \
64
m = dx / (dy); \
65
m1 = m + 1; \
66
incr1 = 2 * dx - 2 * (dy) * m1; \
67
incr2 = 2 * dx - 2 * (dy) * m; \
68
d = -2 * m * (dy) + 2 * dx; \
69
} \
70
} \
71
}
72
73
#define BRESINCRPGON(d, minval, m, m1, incr1, incr2) { \
74
if (m1 > 0) { \
75
if (d > 0) { \
76
minval += m1; \
77
d += incr1; \
78
} \
79
else { \
80
minval += m; \
81
d += incr2; \
82
} \
83
} else {\
84
if (d >= 0) { \
85
minval += m1; \
86
d += incr1; \
87
} \
88
else { \
89
minval += m; \
90
d += incr2; \
91
} \
92
} \
93
}
94
95
96
/*
97
* This structure contains all of the information needed
98
* to run the bresenham algorithm.
99
* The variables may be hardcoded into the declarations
100
* instead of using this structure to make use of
101
* register declarations.
102
*/
103
typedef
struct
{
104
int
minor_axis;
/* minor axis */
105
int
d;
/* decision variable */
106
int
m, m1;
/* slope and slope+1 */
107
int
incr1, incr2;
/* error increments */
108
}
BRESINFO
;
109
110
111
#define BRESINITPGONSTRUCT(dmaj, min1, min2, bres) \
112
BRESINITPGON(dmaj, min1, min2, bres.minor_axis, bres.d, \
113
bres.m, bres.m1, bres.incr1, bres.incr2)
114
115
#define BRESINCRPGONSTRUCT(bres) \
116
BRESINCRPGON(bres.d, bres.minor_axis, bres.m, bres.m1, bres.incr1, bres.incr2)
117
118
119
120
/*
121
* These are the data structures needed to scan
122
* convert regions. Two different scan conversion
123
* methods are available -- the even-odd method, and
124
* the winding number method.
125
* The even-odd rule states that a point is inside
126
* the polygon if a ray drawn from that point in any
127
* direction will pass through an odd number of
128
* path segments.
129
* By the winding number rule, a point is decided
130
* to be inside the polygon if a ray drawn from that
131
* point in any direction passes through a different
132
* number of clockwise and counter-clockwise path
133
* segments.
134
*
135
* These data structures are adapted somewhat from
136
* the algorithm in (Foley/Van Dam) for scan converting
137
* polygons.
138
* The basic algorithm is to start at the top (smallest y)
139
* of the polygon, stepping down to the bottom of
140
* the polygon by incrementing the y coordinate. We
141
* keep a list of edges which the current scanline crosses,
142
* sorted by x. This list is called the Active Edge Table (AET)
143
* As we change the y-coordinate, we update each entry in
144
* in the active edge table to reflect the edges new xcoord.
145
* This list must be sorted at each scanline in case
146
* two edges intersect.
147
* We also keep a data structure known as the Edge Table (ET),
148
* which keeps track of all the edges which the current
149
* scanline has not yet reached. The ET is basically a
150
* list of ScanLineList structures containing a list of
151
* edges which are entered at a given scanline. There is one
152
* ScanLineList per scanline at which an edge is entered.
153
* When we enter a new edge, we move it from the ET to the AET.
154
*
155
* From the AET, we can implement the even-odd rule as in
156
* (Foley/Van Dam).
157
* The winding number rule is a little trickier. We also
158
* keep the EdgeTableEntries in the AET linked by the
159
* nextWETE (winding EdgeTableEntry) link. This allows
160
* the edges to be linked just as before for updating
161
* purposes, but only uses the edges linked by the nextWETE
162
* link as edges representing spans of the polygon to
163
* drawn (as with the even-odd rule).
164
*/
165
166
/*
167
* for the winding number rule
168
*/
169
//#define CLOCKWISE 1
170
//#define COUNTERCLOCKWISE -1
171
172
typedef
struct
_EdgeTableEntry
{
173
int
ymax
;
/* ycoord at which we exit this edge. */
174
BRESINFO
bres
;
/* Bresenham info to run the edge */
175
struct
_EdgeTableEntry
*
next
;
/* next in the list */
176
struct
_EdgeTableEntry
*
back
;
/* for insertion sort */
177
struct
_EdgeTableEntry
*
nextWETE
;
/* for winding num rule */
178
int
ClockWise
;
/* flag for winding number rule */
179
}
EdgeTableEntry
;
180
181
182
typedef
struct
_ScanLineList
{
183
int
scanline
;
/* the scanline represented */
184
EdgeTableEntry
*
edgelist
;
/* header node */
185
struct
_ScanLineList
*
next
;
/* next in the list */
186
}
ScanLineList
;
187
188
189
typedef
struct
{
190
int
ymax;
/* ymax for the polygon */
191
int
ymin;
/* ymin for the polygon */
192
ScanLineList
scanlines;
/* header node */
193
}
EdgeTable
;
194
195
196
/*
197
* Here is a struct to help with storage allocation
198
* so we can allocate a big chunk at a time, and then take
199
* pieces from this heap when we need to.
200
*/
201
#define SLLSPERBLOCK 25
202
203
typedef
struct
_ScanLineListBlock
{
204
ScanLineList
SLLs
[
SLLSPERBLOCK
];
205
struct
_ScanLineListBlock
*
next
;
206
}
ScanLineListBlock
;
207
208
209
210
/*
211
*
212
* a few macros for the inner loops of the fill code where
213
* performance considerations don't allow a procedure call.
214
*
215
* Evaluate the given edge at the given scanline.
216
* If the edge has expired, then we leave it and fix up
217
* the active edge table; otherwise, we increment the
218
* x value to be ready for the next scanline.
219
* The winding number rule is in effect, so we must notify
220
* the caller when the edge has been removed so he
221
* can reorder the Winding Active Edge Table.
222
*/
223
#define EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET) { \
224
if (pAET->ymax == y) {
/* leaving this edge */
\
225
pPrevAET->next = pAET->next; \
226
pAET = pPrevAET->next; \
227
fixWAET = 1; \
228
if (pAET) \
229
pAET->back = pPrevAET; \
230
} \
231
else { \
232
BRESINCRPGONSTRUCT(pAET->bres) \
233
pPrevAET = pAET; \
234
pAET = pAET->next; \
235
} \
236
}
237
238
239
/*
240
* Evaluate the given edge at the given scanline.
241
* If the edge has expired, then we leave it and fix up
242
* the active edge table; otherwise, we increment the
243
* x value to be ready for the next scanline.
244
* The even-odd rule is in effect.
245
*/
246
#define EVALUATEEDGEEVENODD(pAET, pPrevAET, y) { \
247
if (pAET->ymax == y) {
/* leaving this edge */
\
248
pPrevAET->next = pAET->next; \
249
pAET = pPrevAET->next; \
250
if (pAET) \
251
pAET->back = pPrevAET; \
252
} \
253
else { \
254
BRESINCRPGONSTRUCT(pAET->bres) \
255
pPrevAET = pAET; \
256
pAET = pAET->next; \
257
} \
258
}
259
260
261
#endif
BRESINFO
Definition:
line:100
_ScanLineList::scanline
int scanline
Definition:
line:180
_ScanLineList
Definition:
line:179
_EdgeTableEntry::ClockWise
int ClockWise
Definition:
line:175
_ScanLineListBlock::SLLs
ScanLineList SLLs[SLLSPERBLOCK]
Definition:
line:201
EdgeTable
Definition:
line:186
_ScanLineList::next
struct _ScanLineList * next
Definition:
line:182
_ScanLineList::edgelist
EdgeTableEntry * edgelist
Definition:
line:181
_ScanLineListBlock::next
struct _ScanLineListBlock * next
Definition:
line:202
ScanLineList
struct _ScanLineList ScanLineList
_EdgeTableEntry::bres
BRESINFO bres
Definition:
line:171
_EdgeTableEntry::next
struct _EdgeTableEntry * next
Definition:
line:172
SLLSPERBLOCK
#define SLLSPERBLOCK
Definition:
line:198
ScanLineListBlock
struct _ScanLineListBlock ScanLineListBlock
_ScanLineListBlock
Definition:
line:200
_EdgeTableEntry::nextWETE
struct _EdgeTableEntry * nextWETE
Definition:
line:174
EdgeTableEntry
struct _EdgeTableEntry EdgeTableEntry
_EdgeTableEntry::back
struct _EdgeTableEntry * back
Definition:
line:173
_EdgeTableEntry::ymax
int ymax
Definition:
line:170
_EdgeTableEntry
Definition:
line:169
Generated by
1.8.20