|
|
1.1 root 1: /***********************************************************
2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4:
5: All Rights Reserved
6:
7: Permission to use, copy, modify, and distribute this software and its
8: documentation for any purpose and without fee is hereby granted,
9: provided that the above copyright notice appear in all copies and that
10: both that copyright notice and this permission notice appear in
11: supporting documentation, and that the names of Digital or MIT not be
12: used in advertising or publicity pertaining to distribution of the
13: software without specific, written prior permission.
14:
15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21: SOFTWARE.
22:
23: ******************************************************************/
24: /* $Header: miwidedash.c,v 1.13 87/08/31 17:01:06 toddb Exp $ */
25: /* Author: Todd "Mr. Wide Line" Newman */
26:
27: #include "X.h"
28: #include "Xprotostr.h"
29: #include "miscstruct.h"
30: #include "mistruct.h"
31: #include "scrnintstr.h"
32: #include "windowstr.h"
33: #include "gcstruct.h"
34: #include "pixmapstr.h"
35: #include "mifpoly.h"
36:
37: #define GCVALSALU 0
38: #define GCVALSFORE 1
39: #define GCVALSBACK 2
40: #define GCVALSWIDTH 3
41: #define GCVALSCAPSTYLE 4
42: #define GCVALSARCMODE 5
43: static int gcvals[] = {GXcopy, 1, 0, 0, 0, ArcChord};
44:
45: /* Neither Fish nor Fowl, it's a Wide Dashed Line. */
46: /* Actually, wide, dashed lines Are pretty foul. (You knew that was coming,
47: * didn't you.) */
48:
49: /* MIWIDEDASH -- Public entry for PolyLine Requests when the GC speicifies
50: * that we must be dashing (All Hail Errol Flynn)
51: *
52: * We must use the raster op to decide how whether we will draw directly into
53: * the Drawable or squeegee bits through a scratch pixmap to avoid the dash
54: * interfering with itself.
55: *
56: * miDashLine will convert the poly line we were called with into the
57: * appropriate set of line segments.
58: * Based on the dash style we then draw the segments. For OnOff dashes we
59: * draw every other segment and cap each segment. For DoubleDashes, we
60: * draw every other segment starting with the first in the foreground color,
61: * then draw every other segment starting with the second in the background
62: * color. Then we cap the first and last segments "by hand."
63: */
64: void
65: miWideDash(pDraw, pGC, mode, npt, pPtsIn)
66: DrawablePtr pDraw;
67: GCPtr pGC;
68: int mode;
69: int npt;
70: DDXPointPtr pPtsIn;
71: {
72:
73: SppPointPtr pPts, ppt;
74: int nseg, which, whichPrev, i, j, xOrg, yOrg, width,
75: fTricky, arcmode, xMin, xMax, yMin, yMax,
76: dxi, dyi, gcflags;
77: unsigned long oldfore, newfore;
78: miDashPtr dashes;
79: double dy, dx, m;
80: Bool IsDoubleDash = (pGC->lineStyle == LineDoubleDash),
81: fXmajor;
82: SppPointRec pt, PointStash[4], PolyPoints[4];
83: DDXPointPtr pPtIn;
84: DrawablePtr pDrawTo;
85: GCPtr pGCTo;
86:
87:
88: m = EPSILON;
89: if (mode == CoordModePrevious)
90: {
91: DDXPointPtr pptT;
92: int nptTmp;
93:
94: pptT = pPtsIn + 1;
95: nptTmp = npt - 1;
96: while (nptTmp--)
97: {
98: pptT->x += (pptT-1)->x;
99: pptT->y += (pptT-1)->y;
100: pptT++;
101: }
102: }
103:
104: width = pGC->lineWidth;
105: switch(pGC->alu)
106: {
107: case GXclear: /* 0 */
108: case GXcopy: /* src */
109: case GXcopyInverted: /* NOT src */
110: case GXset: /* 1 */
111: fTricky = FALSE;
112: xOrg = yOrg = 0;
113: pDrawTo = pDraw;
114: pGCTo = pGC;
115: if(pGCTo->arcMode != ArcChord)
116: {
117: arcmode = pGCTo->arcMode;
118: DoChangeGC(pGCTo, GCArcMode, &gcvals[GCVALSARCMODE], 0);
119: ValidateGC(pDrawTo, pGCTo);
120: }
121: else
122: arcmode = ArcChord;
123:
124: break;
125: case GXand: /* src AND dst */
126: case GXandReverse: /* src AND NOT dst */
127: case GXandInverted: /* NOT src AND dst */
128: case GXnoop: /* dst */
129: case GXxor: /* src XOR dst */
130: case GXor : /* src OR dst */
131: case GXnor: /* NOT src AND NOT dst */
132: case GXequiv: /* NOT src XOR dst */
133: case GXinvert: /* NOT dst */
134: case GXorReverse: /* src OR NOT dst */
135: case GXorInverted: /* NOT src OR dst */
136: case GXnand: /* NOT src OR NOT dst */
137: fTricky = TRUE;
138: yMin = yMax = pPtsIn[0].y;
139: xMin = xMax = pPtsIn[0].x;
140:
141: for (i = 1; i < npt; i++)
142: {
143: xMin = min(xMin, pPtsIn[i].x);
144: xMax = max(xMax, pPtsIn[i].x);
145: yMin = min(yMin, pPtsIn[i].y);
146: yMax = max(yMax, pPtsIn[i].y);
147: }
148: xOrg = xMin - (width + 1)/2;
149: yOrg = yMin - (width + 1)/2;
150: dxi = xMax - xMin + width;
151: dyi = yMax - yMin + width;
152: pDrawTo = (DrawablePtr) (*pDraw->pScreen->CreatePixmap)
153: (pDraw->pScreen, dxi, dyi, 1, XYBitmap);
154: pGCTo = GetScratchGC(1, pDraw->pScreen);
155: gcvals[GCVALSWIDTH] = width;
156: gcvals[GCVALSCAPSTYLE] = pGC->capStyle;
157: gcflags = GCFunction | GCForeground | GCBackground | GCLineWidth |
158: GCCapStyle;
159: if(pGCTo->arcMode != ArcChord)
160: gcflags |= GCArcMode;
161: DoChangeGC(pGCTo, gcflags, gcvals, 0);
162: ValidateGC(pDrawTo, pGCTo);
163: miClearDrawable(pDrawTo, pGCTo);
164:
165: }
166:
167: dashes = miDashLine(npt, pPtsIn,
168: pGC->numInDashList, pGC->dash, pGC->dashOffset, &nseg);
169: if(!(pPts = (SppPointPtr) Xalloc((nseg + 1) * sizeof(SppPointRec))))
170: {
171: Xfree(dashes);
172: if(fTricky)
173: (*pDraw->pScreen->DestroyPixmap)(pDrawTo);
174: return;
175: }
176: ppt = pPts;
177: pPtIn = pPtsIn;
178: whichPrev = EVEN_DASH;
179:
180: j = 0;
181: for(i = 0; i < nseg + 1; i++)
182: {
183: if(dashes[i].newLine)
184: {
185: /* calculate slope of the line */
186: dx = (double) ((pPtsIn + 1)->x - pPtIn->x);
187: dy = (double) ((pPtsIn + 1)->y - pPtIn->y);
188: pPtIn++;
189: /* use slope of line to figure out how to use error term */
190: fXmajor = (fabs(dx) > fabs(dy));
191: if(fXmajor)
192: m = !ISZERO(dx) ? (dy/dx) : EPSILON;
193: else
194: m = !ISZERO(dy) ? (dx/dy) : EPSILON;
195: }
196: /* Add this point to our list, adjusting the error term as needed */
197: ppt->x = (double) dashes[i].pt.x;
198: ppt->y = (double) dashes[i].pt.y;
199:
200: if(i < 2 || i > nseg - 2)
201: {
202: PointStash[j++] = *ppt;
203: }
204: ppt++;
205: which = dashes[i].which;
206: if(which != whichPrev)
207: {
208: if(which == ODD_DASH)
209: {
210: /* Display the collect line */
211: (*pGC->LineHelper)(pDrawTo, pGCTo, !IsDoubleDash,
212: ppt - pPts, pPts, xOrg, yOrg);
213: }
214: /* Reset the line and start a new dash */
215: pPts[0] = ppt[-1];
216: ppt = &pPts[1];
217: whichPrev = which;
218: }
219:
220: }
221: if(IsDoubleDash)
222: {
223: ppt = pPts;
224: pPtIn = pPtsIn;
225: whichPrev = EVEN_DASH;
226:
227: /* cap the first (and maybe the last) line segment(s) appropriately */
228: if(pGC->capStyle == CapProjecting)
229: {
230: pt = miExtendSegment(PointStash[0], PointStash[1], width/2);
231: miGetPts(pt, PointStash[0],
232: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], &PolyPoints[3],
233: width);
234: miFillSppPoly(pDrawTo, pGCTo, 4, PolyPoints, xOrg, yOrg);
235: if(dashes[nseg].which == EVEN_DASH)
236: {
237: pt = miExtendSegment(PointStash[3], PointStash[2], width/2);
238: miGetPts(pt, PointStash[3],
239: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2],
240: &PolyPoints[3], width);
241: miFillSppPoly(pDrawTo, pGCTo, 4, PolyPoints, xOrg, yOrg);
242: }
243:
244: }
245: else if (pGC->capStyle == CapRound)
246: {
247: miGetPts(PointStash[0], PointStash[1],
248: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], &PolyPoints[3],
249: width);
250: miRoundCap(pDrawTo, pGCTo, PointStash[0], PointStash[1],
251: PolyPoints[0], PolyPoints[3], FirstEnd, xOrg, yOrg);
252: if(dashes[nseg].which == EVEN_DASH)
253: {
254: miGetPts(PointStash[3], PointStash[2],
255: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2],
256: &PolyPoints[3], width);
257: miRoundCap(pDrawTo, pGCTo, PointStash[3], PointStash[2],
258: PolyPoints[3], PolyPoints[0], SecondEnd, xOrg, yOrg);
259: }
260: }
261: oldfore = pGC->fgPixel;
262: newfore = pGC->bgPixel;
263: DoChangeGC(pGCTo, GCForeground, &newfore, 0);
264: ValidateGC(pDrawTo, pGCTo);
265:
266: for(i = 0; i < nseg + 1; i++)
267: {
268: if(dashes[i].newLine)
269: {
270: /* calculate slope of the line */
271: dx = (double) ((pPtIn + 1)->x - pPtIn->x);
272: dy = (double) ((pPtIn + 1)->y - pPtIn->y);
273: /* use slope of line to figure out how to use error term */
274: fXmajor = (fabs(dx) > fabs(dy));
275: if(fXmajor)
276: m = ISZERO(dx) ? (dy/dx) : EPSILON;
277: else
278: m = ISZERO(dy) ? (dx/dy) : EPSILON;
279: pPtIn++;
280: }
281: /* Add this point to our list */
282: ppt->x = (double) dashes[i].pt.x +
283: (fXmajor ? 0.0 : dashes[i].e*m);
284: ppt->y = (double) dashes[i].pt.y +
285: (fXmajor ? dashes[i].e*m : 0.0);
286: ppt++;
287: which = dashes[i].which;
288: if(which != whichPrev)
289: {
290: if(which == EVEN_DASH)
291: {
292: /* Display the collected line */
293: (*pGC->LineHelper)(pDrawTo, pGCTo, FALSE,
294: ppt - pPts, pPts, xOrg, yOrg);
295: }
296: /* Reset the line and start a new dash */
297: pPts[0] = ppt[-1];
298: ppt = &pPts[1];
299: whichPrev = which;
300: }
301:
302: }
303:
304: /* cap the last line segments appropriately */
305: if(dashes[nseg].which == ODD_DASH)
306: {
307: if(pGC->capStyle == CapProjecting)
308: {
309: pt = miExtendSegment(PointStash[3], PointStash[2], width/2);
310: miGetPts(pt, PointStash[3],
311: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2],
312: &PolyPoints[3], width);
313: miFillSppPoly(pDrawTo, pGCTo, 4, PolyPoints, xOrg, yOrg);
314:
315: }
316: else if (pGC->capStyle == CapRound)
317: {
318: miGetPts(PointStash[3], PointStash[2],
319: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2],
320: &PolyPoints[3], width);
321: miRoundCap(pDrawTo, pGCTo, PointStash[3], PointStash[2],
322: PolyPoints[3], PolyPoints[0], SecondEnd, xOrg, yOrg);
323: }
324: }
325: DoChangeGC(pGCTo, GCForeground, &oldfore, 0);
326: }
327: if(arcmode != ArcChord)
328: {
329: DoChangeGC(pGCTo, GCArcMode, &gcvals[GCVALSARCMODE], 0);
330: }
331: ValidateGC(pDrawTo, pGCTo);
332: if(fTricky)
333: {
334: if (pGC->miTranslate && (pDraw->type == DRAWABLE_WINDOW) )
335: {
336: xOrg += ((WindowPtr)pDraw)->absCorner.x;
337: yOrg += ((WindowPtr)pDraw)->absCorner.y;
338: }
339:
340: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dxi, dyi, xOrg, yOrg);
341: (*pDraw->pScreen->DestroyPixmap)(pDrawTo);
342: FreeScratchGC(pGCTo);
343: }
344: Xfree(dashes);
345: Xfree(pPts);
346: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.