1
/* $XFree86: xc/programs/Xserver/mi/mizerclip.c,v 1.1 1999/10/13 22:33:13 dawes Exp $ */
2
/***********************************************************
4
Copyright 1987, 1998 The Open Group
8
The above copyright notice and this permission notice shall be included in
9
all copies or substantial portions of the Software.
11
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
15
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
Except as contained in this notice, the name of The Open Group shall not be
19
used in advertising or otherwise to promote the sale, use or other dealings
20
in this Software without prior written authorization from The Open Group.
23
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
Permission to use, copy, modify, and distribute this software and its
28
documentation for any purpose and without fee is hereby granted,
29
provided that the above copyright notice appear in all copies and that
30
both that copyright notice and this permission notice appear in
31
supporting documentation, and that the name of Digital not be
32
used in advertising or publicity pertaining to distribution of the
33
software without specific, written prior permission.
35
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43
******************************************************************/
51
The bresenham error equation used in the mi/mfb/cfb line routines is:
54
dx = difference in raw X coordinates
55
dy = difference in raw Y coordinates
56
M = # of steps in X direction
57
N = # of steps in Y direction
58
B = 0 to prefer diagonal steps in a given octant,
59
1 to prefer axial steps in a given octant
62
e = 2Mdy - 2Ndx - dx - B
66
e = 2Ndx - 2Mdy - dy - B
69
At the start of the line, we have taken 0 X steps and 0 Y steps,
72
X major e = 2Mdy - 2Ndx - dx - B
75
Y major e = 2Ndx - 2Mdy - dy - B
78
At the end of the line, we have taken dx X steps and dy Y steps,
81
X major e = 2Mdy - 2Ndx - dx - B
82
= 2dxdy - 2dydx - dx - B
84
Y major e = 2Ndx - 2Mdy - dy - B
85
= 2dydx - 2dxdy - dy - B
88
Thus, the error term is the same at the start and end of the line.
90
Let us consider clipping an X coordinate. There are 4 cases which
91
represent the two independent cases of clipping the start vs. the
92
end of the line and an X major vs. a Y major line. In any of these
93
cases, we know the number of X steps (M) and we wish to find the
94
number of Y steps (N). Thus, we will solve our error term equation.
95
If we are clipping the start of the line, we will find the smallest
96
N that satisfies our error term inequality. If we are clipping the
97
end of the line, we will find the largest number of Y steps that
98
satisfies the inequality. In that case, since we are representing
99
the Y steps as (dy - N), we will actually want to solve for the
100
smallest N in that equation.
102
Case 1: X major, starting X coordinate moved by M steps
104
-2dx <= 2Mdy - 2Ndx - dx - B < 0
105
2Ndx <= 2Mdy - dx - B + 2dx 2Ndx > 2Mdy - dx - B
106
2Ndx <= 2Mdy + dx - B N > (2Mdy - dx - B) / 2dx
107
N <= (2Mdy + dx - B) / 2dx
109
Since we are trying to find the smallest N that satisfies these
110
equations, we should use the > inequality to find the smallest:
112
N = floor((2Mdy - dx - B) / 2dx) + 1
113
= floor((2Mdy - dx - B + 2dx) / 2dx)
114
= floor((2Mdy + dx - B) / 2dx)
116
Case 1b: X major, ending X coordinate moved to M steps
118
Same derivations as Case 1, but we want the largest N that satisfies
119
the equations, so we use the <= inequality:
121
N = floor((2Mdy + dx - B) / 2dx)
123
Case 2: X major, ending X coordinate moved by M steps
125
-2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
126
-2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
127
-2dx <= 2Ndx - 2Mdy - dx - B < 0
128
2Ndx >= 2Mdy + dx + B - 2dx 2Ndx < 2Mdy + dx + B
129
2Ndx >= 2Mdy - dx + B N < (2Mdy + dx + B) / 2dx
130
N >= (2Mdy - dx + B) / 2dx
132
Since we are trying to find the highest number of Y steps that
133
satisfies these equations, we need to find the smallest N, so
134
we should use the >= inequality to find the smallest:
136
N = ceiling((2Mdy - dx + B) / 2dx)
137
= floor((2Mdy - dx + B + 2dx - 1) / 2dx)
138
= floor((2Mdy + dx + B - 1) / 2dx)
140
Case 2b: X major, starting X coordinate moved to M steps from end
142
Same derivations as Case 2, but we want the smallest number of Y
143
steps, so we want the highest N, so we use the < inequality:
145
N = ceiling((2Mdy + dx + B) / 2dx) - 1
146
= floor((2Mdy + dx + B + 2dx - 1) / 2dx) - 1
147
= floor((2Mdy + dx + B + 2dx - 1 - 2dx) / 2dx)
148
= floor((2Mdy + dx + B - 1) / 2dx)
150
Case 3: Y major, starting X coordinate moved by M steps
152
-2dy <= 2Ndx - 2Mdy - dy - B < 0
153
2Ndx >= 2Mdy + dy + B - 2dy 2Ndx < 2Mdy + dy + B
154
2Ndx >= 2Mdy - dy + B N < (2Mdy + dy + B) / 2dx
155
N >= (2Mdy - dy + B) / 2dx
157
Since we are trying to find the smallest N that satisfies these
158
equations, we should use the >= inequality to find the smallest:
160
N = ceiling((2Mdy - dy + B) / 2dx)
161
= floor((2Mdy - dy + B + 2dx - 1) / 2dx)
162
= floor((2Mdy - dy + B - 1) / 2dx) + 1
164
Case 3b: Y major, ending X coordinate moved to M steps
166
Same derivations as Case 3, but we want the largest N that satisfies
167
the equations, so we use the < inequality:
169
N = ceiling((2Mdy + dy + B) / 2dx) - 1
170
= floor((2Mdy + dy + B + 2dx - 1) / 2dx) - 1
171
= floor((2Mdy + dy + B + 2dx - 1 - 2dx) / 2dx)
172
= floor((2Mdy + dy + B - 1) / 2dx)
174
Case 4: Y major, ending X coordinate moved by M steps
176
-2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
177
-2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
178
-2dy <= 2Mdy - 2Ndx - dy - B < 0
179
2Ndx <= 2Mdy - dy - B + 2dy 2Ndx > 2Mdy - dy - B
180
2Ndx <= 2Mdy + dy - B N > (2Mdy - dy - B) / 2dx
181
N <= (2Mdy + dy - B) / 2dx
183
Since we are trying to find the highest number of Y steps that
184
satisfies these equations, we need to find the smallest N, so
185
we should use the > inequality to find the smallest:
187
N = floor((2Mdy - dy - B) / 2dx) + 1
189
Case 4b: Y major, starting X coordinate moved to M steps from end
191
Same analysis as Case 4, but we want the smallest number of Y steps
192
which means the largest N, so we use the <= inequality:
194
N = floor((2Mdy + dy - B) / 2dx)
196
Now let's try the Y coordinates, we have the same 4 cases.
198
Case 5: X major, starting Y coordinate moved by N steps
200
-2dx <= 2Mdy - 2Ndx - dx - B < 0
201
2Mdy >= 2Ndx + dx + B - 2dx 2Mdy < 2Ndx + dx + B
202
2Mdy >= 2Ndx - dx + B M < (2Ndx + dx + B) / 2dy
203
M >= (2Ndx - dx + B) / 2dy
205
Since we are trying to find the smallest M, we use the >= inequality:
207
M = ceiling((2Ndx - dx + B) / 2dy)
208
= floor((2Ndx - dx + B + 2dy - 1) / 2dy)
209
= floor((2Ndx - dx + B - 1) / 2dy) + 1
211
Case 5b: X major, ending Y coordinate moved to N steps
213
Same derivations as Case 5, but we want the largest M that satisfies
214
the equations, so we use the < inequality:
216
M = ceiling((2Ndx + dx + B) / 2dy) - 1
217
= floor((2Ndx + dx + B + 2dy - 1) / 2dy) - 1
218
= floor((2Ndx + dx + B + 2dy - 1 - 2dy) / 2dy)
219
= floor((2Ndx + dx + B - 1) / 2dy)
221
Case 6: X major, ending Y coordinate moved by N steps
223
-2dx <= 2(dx - M)dy - 2(dy - N)dx - dx - B < 0
224
-2dx <= 2dxdy - 2Mdy - 2dxdy + 2Ndx - dx - B < 0
225
-2dx <= 2Ndx - 2Mdy - dx - B < 0
226
2Mdy <= 2Ndx - dx - B + 2dx 2Mdy > 2Ndx - dx - B
227
2Mdy <= 2Ndx + dx - B M > (2Ndx - dx - B) / 2dy
228
M <= (2Ndx + dx - B) / 2dy
230
Largest # of X steps means smallest M, so use the > inequality:
232
M = floor((2Ndx - dx - B) / 2dy) + 1
234
Case 6b: X major, starting Y coordinate moved to N steps from end
236
Same derivations as Case 6, but we want the smallest # of X steps
237
which means the largest M, so use the <= inequality:
239
M = floor((2Ndx + dx - B) / 2dy)
241
Case 7: Y major, starting Y coordinate moved by N steps
243
-2dy <= 2Ndx - 2Mdy - dy - B < 0
244
2Mdy <= 2Ndx - dy - B + 2dy 2Mdy > 2Ndx - dy - B
245
2Mdy <= 2Ndx + dy - B M > (2Ndx - dy - B) / 2dy
246
M <= (2Ndx + dy - B) / 2dy
248
To find the smallest M, use the > inequality:
250
M = floor((2Ndx - dy - B) / 2dy) + 1
251
= floor((2Ndx - dy - B + 2dy) / 2dy)
252
= floor((2Ndx + dy - B) / 2dy)
254
Case 7b: Y major, ending Y coordinate moved to N steps
256
Same derivations as Case 7, but we want the largest M that satisfies
257
the equations, so use the <= inequality:
259
M = floor((2Ndx + dy - B) / 2dy)
261
Case 8: Y major, ending Y coordinate moved by N steps
263
-2dy <= 2(dy - N)dx - 2(dx - M)dy - dy - B < 0
264
-2dy <= 2dxdy - 2Ndx - 2dxdy + 2Mdy - dy - B < 0
265
-2dy <= 2Mdy - 2Ndx - dy - B < 0
266
2Mdy >= 2Ndx + dy + B - 2dy 2Mdy < 2Ndx + dy + B
267
2Mdy >= 2Ndx - dy + B M < (2Ndx + dy + B) / 2dy
268
M >= (2Ndx - dy + B) / 2dy
270
To find the highest X steps, find the smallest M, use the >= inequality:
272
M = ceiling((2Ndx - dy + B) / 2dy)
273
= floor((2Ndx - dy + B + 2dy - 1) / 2dy)
274
= floor((2Ndx + dy + B - 1) / 2dy)
276
Case 8b: Y major, starting Y coordinate moved to N steps from the end
278
Same derivations as Case 8, but we want to find the smallest # of X
279
steps which means the largest M, so we use the < inequality:
281
M = ceiling((2Ndx + dy + B) / 2dy) - 1
282
= floor((2Ndx + dy + B + 2dy - 1) / 2dy) - 1
283
= floor((2Ndx + dy + B + 2dy - 1 - 2dy) / 2dy)
284
= floor((2Ndx + dy + B - 1) / 2dy)
286
So, our equations are:
288
1: X major move x1 to x1+M floor((2Mdy + dx - B) / 2dx)
289
1b: X major move x2 to x1+M floor((2Mdy + dx - B) / 2dx)
290
2: X major move x2 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
291
2b: X major move x1 to x2-M floor((2Mdy + dx + B - 1) / 2dx)
293
3: Y major move x1 to x1+M floor((2Mdy - dy + B - 1) / 2dx) + 1
294
3b: Y major move x2 to x1+M floor((2Mdy + dy + B - 1) / 2dx)
295
4: Y major move x2 to x2-M floor((2Mdy - dy - B) / 2dx) + 1
296
4b: Y major move x1 to x2-M floor((2Mdy + dy - B) / 2dx)
298
5: X major move y1 to y1+N floor((2Ndx - dx + B - 1) / 2dy) + 1
299
5b: X major move y2 to y1+N floor((2Ndx + dx + B - 1) / 2dy)
300
6: X major move y2 to y2-N floor((2Ndx - dx - B) / 2dy) + 1
301
6b: X major move y1 to y2-N floor((2Ndx + dx - B) / 2dy)
303
7: Y major move y1 to y1+N floor((2Ndx + dy - B) / 2dy)
304
7b: Y major move y2 to y1+N floor((2Ndx + dy - B) / 2dy)
305
8: Y major move y2 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
306
8b: Y major move y1 to y2-N floor((2Ndx + dy + B - 1) / 2dy)
308
We have the following constraints on all of the above terms:
310
0 < M,N <= 2^15 2^15 can be imposed by miZeroClipLine
311
0 <= dx/dy <= 2^16 - 1
314
The floor in all of the above equations can be accomplished with a
315
simple C divide operation provided that both numerator and denominator
318
Since dx,dy >= 0 and since moving an X coordinate implies that dx != 0
319
and moving a Y coordinate implies dy != 0, we know that the denominators
322
For all lines, (-B) and (B-1) are both either 0 or -1, depending on the
323
bias. Thus, we have to show that the 2MNdxy +/- dxy terms are all >= 1
324
or > 0 to prove that the numerators are positive (or zero).
326
For X Major lines we know that dx > 0 and since 2Mdy is >= 0 due to the
327
constraints, the first four equations all have numerators >= 0.
329
For the second four equations, M > 0, so 2Mdy >= 2dy so (2Mdy - dy) >= dy
330
So (2Mdy - dy) > 0, since they are Y major lines. Also, (2Mdy + dy) >= 3dy
331
or (2Mdy + dy) > 0. So all of their numerators are >= 0.
333
For the third set of four equations, N > 0, so 2Ndx >= 2dx so (2Ndx - dx)
334
>= dx > 0. Similarly (2Ndx + dx) >= 3dx > 0. So all numerators >= 0.
336
For the fourth set of equations, dy > 0 and 2Ndx >= 0, so all numerators
339
To consider overflow, consider the case of 2 * M,N * dx,dy + dx,dy. This
340
is bounded <= 2 * 2^15 * (2^16 - 1) + (2^16 - 1)
341
<= 2^16 * (2^16 - 1) + (2^16 - 1)
342
<= 2^32 - 2^16 + 2^16 - 1
344
Since the (-B) and (B-1) terms are all 0 or -1, the maximum value of
345
the numerator is therefore (2^32 - 1), which does not overflow an unsigned
350
/* Bit codes for the terms of the 16 clipping equations defined below. */
352
#define T_2NDX (1 << 0)
353
#define T_2MDY (0) /* implicit term */
354
#define T_DXNOTY (1 << 1)
355
#define T_DYNOTX (0) /* implicit term */
356
#define T_SUBDXORY (1 << 2)
357
#define T_ADDDX (T_DXNOTY) /* composite term */
358
#define T_SUBDX (T_DXNOTY | T_SUBDXORY) /* composite term */
359
#define T_ADDDY (T_DYNOTX) /* composite term */
360
#define T_SUBDY (T_DYNOTX | T_SUBDXORY) /* composite term */
361
#define T_BIASSUBONE (1 << 3)
362
#define T_SUBBIAS (0) /* implicit term */
363
#define T_DIV2DX (1 << 4)
364
#define T_DIV2DY (0) /* implicit term */
365
#define T_ADDONE (1 << 5)
367
/* Bit masks defining the 16 equations used in miZeroClipLine. */
369
#define EQN1 (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
370
#define EQN1B (T_2MDY | T_ADDDX | T_SUBBIAS | T_DIV2DX)
371
#define EQN2 (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
372
#define EQN2B (T_2MDY | T_ADDDX | T_BIASSUBONE | T_DIV2DX)
374
#define EQN3 (T_2MDY | T_SUBDY | T_BIASSUBONE | T_DIV2DX | T_ADDONE)
375
#define EQN3B (T_2MDY | T_ADDDY | T_BIASSUBONE | T_DIV2DX)
376
#define EQN4 (T_2MDY | T_SUBDY | T_SUBBIAS | T_DIV2DX | T_ADDONE)
377
#define EQN4B (T_2MDY | T_ADDDY | T_SUBBIAS | T_DIV2DX)
379
#define EQN5 (T_2NDX | T_SUBDX | T_BIASSUBONE | T_DIV2DY | T_ADDONE)
380
#define EQN5B (T_2NDX | T_ADDDX | T_BIASSUBONE | T_DIV2DY)
381
#define EQN6 (T_2NDX | T_SUBDX | T_SUBBIAS | T_DIV2DY | T_ADDONE)
382
#define EQN6B (T_2NDX | T_ADDDX | T_SUBBIAS | T_DIV2DY)
384
#define EQN7 (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
385
#define EQN7B (T_2NDX | T_ADDDY | T_SUBBIAS | T_DIV2DY)
386
#define EQN8 (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
387
#define EQN8B (T_2NDX | T_ADDDY | T_BIASSUBONE | T_DIV2DY)
391
* returns: 1 for partially clipped line
392
* -1 for completely clipped line
396
miZeroClipLine(int xmin, int ymin, int xmax, int ymax,
397
int *new_x1, int *new_y1, int *new_x2, int *new_y2,
398
unsigned int adx, unsigned int ady,
399
int *pt1_clipped, int *pt2_clipped, int octant,
400
unsigned int bias, int oc1, int oc2)
407
int x1_orig, y1_orig, x2_orig, y2_orig;
409
int negslope = 0, anchorval = 0;
410
unsigned int eqn = 0;
412
x1 = x1_orig = *new_x1;
413
y1 = y1_orig = *new_y1;
414
x2 = x2_orig = *new_x2;
415
y2 = y2_orig = *new_y2;
420
xmajor = IsXMajorOctant(octant);
421
bias = ((bias >> octant) & 1);
425
if ((oc1 & oc2) != 0) /* trivial reject */
432
else if ((oc1 | oc2) == 0) /* trivial accept */
437
SWAPINT_PAIR(x1, y1, x2, y2);
438
SWAPINT(clip1, clip2);
442
else /* have to clip */
444
/* only clip one point at a time */
447
SWAPINT_PAIR(x1, y1, x2, y2);
448
SWAPINT_PAIR(x1_orig, y1_orig, x2_orig, y2_orig);
450
SWAPINT(clip1, clip2);
457
negslope = IsYDecreasingOctant(octant);
458
utmp = xmin - x1_orig;
459
if (utmp <= 32767) /* clip based on near endpt */
462
eqn = (swapped) ? EQN2 : EQN1;
464
eqn = (swapped) ? EQN4 : EQN3;
467
else /* clip based on far endpt */
469
utmp = x2_orig - xmin;
471
eqn = (swapped) ? EQN1B : EQN2B;
473
eqn = (swapped) ? EQN3B : EQN4B;
475
negslope = !negslope;
479
else if (oc1 & OUT_ABOVE)
481
negslope = IsXDecreasingOctant(octant);
482
utmp = ymin - y1_orig;
483
if (utmp <= 32767) /* clip based on near endpt */
486
eqn = (swapped) ? EQN6 : EQN5;
488
eqn = (swapped) ? EQN8 : EQN7;
491
else /* clip based on far endpt */
493
utmp = y2_orig - ymin;
495
eqn = (swapped) ? EQN5B : EQN6B;
497
eqn = (swapped) ? EQN7B : EQN8B;
499
negslope = !negslope;
503
else if (oc1 & OUT_RIGHT)
505
negslope = IsYDecreasingOctant(octant);
506
utmp = x1_orig - xmax;
507
if (utmp <= 32767) /* clip based on near endpt */
510
eqn = (swapped) ? EQN2 : EQN1;
512
eqn = (swapped) ? EQN4 : EQN3;
515
else /* clip based on far endpt */
518
* Technically since the equations can handle
519
* utmp == 32768, this overflow code isn't
520
* needed since X11 protocol can't generate
521
* a line which goes more than 32768 pixels
522
* to the right of a clip rectangle.
524
utmp = xmax - x2_orig;
526
eqn = (swapped) ? EQN1B : EQN2B;
528
eqn = (swapped) ? EQN3B : EQN4B;
530
negslope = !negslope;
534
else if (oc1 & OUT_BELOW)
536
negslope = IsXDecreasingOctant(octant);
537
utmp = y1_orig - ymax;
538
if (utmp <= 32767) /* clip based on near endpt */
541
eqn = (swapped) ? EQN6 : EQN5;
543
eqn = (swapped) ? EQN8 : EQN7;
546
else /* clip based on far endpt */
549
* Technically since the equations can handle
550
* utmp == 32768, this overflow code isn't
551
* needed since X11 protocol can't generate
552
* a line which goes more than 32768 pixels
553
* below the bottom of a clip rectangle.
555
utmp = ymax - y2_orig;
557
eqn = (swapped) ? EQN5B : EQN6B;
559
eqn = (swapped) ? EQN7B : EQN8B;
561
negslope = !negslope;
567
negslope = !negslope;
569
utmp <<= 1; /* utmp = 2N or 2M */
572
else /* (eqn & T_2MDY) */
575
if (eqn & T_SUBDXORY)
579
else /* (eqn & T_DYNOTX) */
580
if (eqn & T_SUBDXORY)
584
if (eqn & T_BIASSUBONE)
586
else /* (eqn & T_SUBBIAS) */
590
else /* (eqn & T_DIV2DY) */
598
if (eqn & T_2NDX) /* We are calculating X steps */
599
x1 = anchorval + utmp;
600
else /* else, Y steps */
601
y1 = anchorval + utmp;
604
MIOUTCODES(oc1, x1, y1, xmin, ymin, xmax, ymax);
613
*pt1_clipped = clip1;
614
*pt2_clipped = clip2;