1/*****************************************************************************
2Copyright 1988, 1989 by Digital Equipment Corporation, Maynard, Massachusetts.
3
4                        All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of Digital not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************************/
23
24#include "x11perf.h"
25
26static XSegment *segments;
27static GC       pgc;
28
29static void
30GenerateSegments(XParms xp, Parms p, Bool ddashed)
31{
32    int     size;
33    int     half;
34    int     i;
35    int     rows;	    /* Number of rows filled in current column      */
36    int     x, y;	    /* base of square to draw in		    */
37    int     x1=0, y1=0, x2=0, y2=0; /* offsets into square		    */
38    int     phase;	    /* how far into 0..8*size we are		    */
39    int     phaseinc;       /* how much to increment phase at each segment  */
40    int     size8;	    /* 8 * size					    */
41    XGCValues   gcv;
42
43    if(ddashed)
44	pgc = xp->ddfggc;
45    else
46	pgc = xp->fggc;
47
48
49    size = p->special;
50    size8 = 8 * size;
51    half = (size + 19) / 20;
52
53    segments = malloc((p->objects) * sizeof(XSegment));
54
55    /* All this x, x1, etc. stuff is to create a pattern that
56	(1) scans down the screen vertically, with each new segment going
57	    into a square of size^2.
58
59	(2) rotates the endpoints clockwise around the square
60
61	(3) rotates by ``large'' steps if we aren't going to paint enough
62	    segments to get full coverage
63
64	(4) uses CapNotLast so we can create segments of length 1 that
65	    nonetheless have a distinct direction
66    */
67
68    x     = half;  y     = half;
69    phase = 0;
70    phaseinc = size8 / p->objects;
71    if (phaseinc == 0) phaseinc = 1;
72    rows = 0;
73
74    for (i = 0; i != p->objects; i++) {
75	switch (phase / size) {
76	case 0:
77	    x1 = 0;
78	    y1 = 0;
79	    x2 = size;
80	    y2 = phase;
81	    break;
82
83	case 1:
84	    x1 = phase % size;
85	    y1 = 0;
86	    x2 = size;
87	    y2 = size;
88	    break;
89
90	case 2:
91	    x1 = size;
92	    y1 = 0;
93	    x2 = size - phase % size;
94	    y2 = size;
95	    break;
96
97	case 3:
98	    x1 = size;
99	    y1 = phase % size;
100	    x2 = 0;
101	    y2 = size;
102	    break;
103
104	case 4:
105	    x1 = size;
106	    y1 = size;
107	    x2 = 0;
108	    y2 = size - phase % size;
109	    break;
110
111	case 5:
112	    x1 = size - phase % size;
113	    y1 = size;
114	    x2 = 0;
115	    y2 = 0;
116	    break;
117
118	case 6:
119	    x1 = 0;
120	    y1 = size;
121	    x2 = phase % size;
122	    y2 = 0;
123	    break;
124
125	case 7:
126	    x1 = 0;
127	    y1 = size - phase % size;
128	    x2 = size;
129	    y2 = 0;
130	    break;
131	} /* end switch */
132
133	segments[i].x1 = x + x1;
134	segments[i].y1 = y + y1;
135	segments[i].x2 = x + x2;
136	segments[i].y2 = y + y2;
137
138	/* Change square to draw segment in */
139	rows++;
140	y += size;
141	if (y >= HEIGHT - size - half || rows == MAXROWS) {
142	    /* Go to next column */
143	    rows = 0;
144	    y = half;
145	    x += size;
146	    if (x >= WIDTH - size - half) {
147		x = half;
148	    }
149	}
150
151	/* Increment phase */
152	phase += phaseinc;
153	if (phase >= size8) phase -= size8;
154
155    }
156
157    gcv.cap_style = CapNotLast;
158
159    if(ddashed) {
160	XChangeGC(xp->d, xp->ddfggc, GCCapStyle, &gcv);
161	XChangeGC(xp->d, xp->ddbggc, GCCapStyle, &gcv);
162    } else {
163	XChangeGC(xp->d, xp->fggc, GCCapStyle, &gcv);
164	XChangeGC(xp->d, xp->bggc, GCCapStyle, &gcv);
165    }
166}
167
168int
169InitSegments(XParms xp, Parms p, int64_t reps)
170{
171    GenerateSegments(xp, p, False);
172    return reps;
173}
174
175int
176InitDashedSegments(XParms xp, Parms p, int64_t reps)
177{
178    char dashes[2];
179
180    GenerateSegments(xp, p, False);
181
182    /* Modify GCs to draw dashed */
183    XSetLineAttributes
184	(xp->d, xp->bggc, 0, LineOnOffDash, CapNotLast, JoinMiter);
185    XSetLineAttributes
186	(xp->d, xp->fggc, 0, LineOnOffDash, CapNotLast, JoinMiter);
187    dashes[0] = 3;   dashes[1] = 2;
188    XSetDashes(xp->d, xp->fggc, 0, dashes, 2);
189    XSetDashes(xp->d, xp->bggc, 0, dashes, 2);
190    return reps;
191}
192
193int
194InitDoubleDashedSegments(XParms xp, Parms p, int64_t reps)
195{
196    char dashes[2];
197
198    GenerateSegments(xp, p, True);
199
200    /* Modify GCs to draw dashed */
201    XSetLineAttributes
202	(xp->d, xp->ddbggc, 0, LineDoubleDash, CapNotLast, JoinMiter);
203    XSetLineAttributes
204	(xp->d, xp->ddfggc, 0, LineDoubleDash, CapNotLast, JoinMiter);
205    dashes[0] = 3;   dashes[1] = 2;
206    XSetDashes(xp->d, xp->ddfggc, 0, dashes, 2);
207    XSetDashes(xp->d, xp->ddbggc, 0, dashes, 2);
208    return reps;
209}
210
211static int
212InitHorizSegmentsWidth(XParms xp, Parms p, int64_t reps, int width)
213{
214    int     size;
215    int     i;
216    int     x, y;	/* base of square to draw in			*/
217    int     y1;		/* y position inside square			*/
218    int     inc;
219    XGCValues   gcv;
220
221    pgc = xp->fggc;
222
223    size = p->special;
224
225    segments = malloc((p->objects) * sizeof(XSegment));
226
227    x = width / 2 + 1;
228    y = width / 2 + 1;
229    y1 = 0;
230    inc = width + 1;
231
232    for (i = 0; i != p->objects; i++) {
233	if (i % 2) {
234	    segments[i].x1 = x + size;
235	    segments[i].x2 = x;
236	    segments[i].y1 = y + (HEIGHT - width - 2) - y1;
237	    segments[i].y2 = y + (HEIGHT - width - 2) - y1;
238            y1 += inc;
239	} else {
240	    segments[i].x1 = x;
241	    segments[i].x2 = x + size;
242	    segments[i].y1 = y + y1;
243	    segments[i].y2 = y + y1;
244	}
245        /* Go to next row */
246	if (y1 >= HEIGHT / 2 - (width + 2)) {
247	    y1 =0;
248	    x += size + inc;
249	    if (x >= WIDTH - size - width)
250		x = width/2 + 1;
251	}
252    }
253    gcv.cap_style = CapNotLast;
254    XChangeGC(xp->d, xp->fggc, GCCapStyle, &gcv);
255    XChangeGC(xp->d, xp->bggc, GCCapStyle, &gcv);
256    return reps;
257}
258
259int
260InitHorizSegments(XParms xp, Parms p, int64_t reps)
261{
262    return InitHorizSegmentsWidth(xp, p, reps, 1);
263}
264
265int
266InitWideHorizSegments(XParms xp, Parms p, int64_t reps)
267{
268    int size = p->special;
269
270    (void)InitHorizSegmentsWidth(xp, p, reps, (int) ((size + 9) / 10));
271
272    XSetLineAttributes(xp->d, xp->bggc, (int) ((size + 9) / 10),
273	LineSolid, CapRound, JoinRound);
274    XSetLineAttributes(xp->d, xp->fggc, (int) ((size + 9) / 10),
275	LineSolid, CapRound, JoinRound);
276
277    return reps;
278}
279
280static int
281InitVertSegmentsWidth(XParms xp, Parms p, int64_t reps, int width)
282{
283    int     size;
284    int     i;
285    int     x, y;	/* base of square to draw in			*/
286    int     x1;		/* x position inside square			*/
287    int     inc;
288    XGCValues   gcv;
289
290    pgc = xp->fggc;
291
292    size = p->special;
293
294    segments = malloc((p->objects) * sizeof(XSegment));
295
296    x = width / 2 + 1;
297    y = width / 2 + 1;
298    x1 = 0;
299    inc = width + 1;
300
301    for (i = 0; i != p->objects; i++) {
302	if (i % 2) {
303	    segments[i].x1 = x + (WIDTH - width - 2) - x1;
304	    segments[i].x2 = x + (WIDTH - width - 2) - x1;
305	    segments[i].y1 = y + size;
306	    segments[i].y2 = y;
307            x1 += inc;
308	} else {
309	    segments[i].x1 = x + x1;
310	    segments[i].x2 = x + x1;
311	    segments[i].y1 = y;
312	    segments[i].y2 = y + size;
313	}
314        /* Go to next column */
315	if (x1 >= WIDTH / 2 - (width + 2)) {
316	    x1 = 0;
317            y += size + inc;
318            if (y >= HEIGHT - size - width)
319                y = width/2 + 1;
320	}
321    }
322    gcv.cap_style = CapNotLast;
323    XChangeGC(xp->d, xp->fggc, GCCapStyle, &gcv);
324    XChangeGC(xp->d, xp->bggc, GCCapStyle, &gcv);
325    return reps;
326}
327
328int
329InitVertSegments(XParms xp, Parms p, int64_t reps)
330{
331    return InitVertSegmentsWidth(xp, p, reps, 1);
332}
333
334int
335InitWideVertSegments(XParms xp, Parms p, int64_t reps)
336{
337    int    size = p->special;
338
339    (void)InitVertSegmentsWidth(xp, p, reps, (size + 9) / 10);
340
341    XSetLineAttributes(xp->d, xp->bggc, (int) ((size + 9) / 10),
342	LineSolid, CapRound, JoinRound);
343    XSetLineAttributes(xp->d, xp->fggc, (int) ((size + 9) / 10),
344	LineSolid, CapRound, JoinRound);
345
346    return reps;
347}
348
349void
350DoSegments(XParms xp, Parms p, int64_t reps)
351{
352    int i;
353
354    for (i = 0; i != reps; i++) {
355        XDrawSegments(xp->d, xp->w, pgc, segments, p->objects);
356        if (pgc == xp->ddbggc)
357            pgc = xp->ddfggc;
358        else if(pgc == xp->ddfggc)
359            pgc = xp->ddbggc;
360        else if (pgc == xp->bggc)
361            pgc = xp->fggc;
362        else
363            pgc = xp->bggc;
364	CheckAbort ();
365    }
366}
367
368void
369EndSegments(XParms xp, Parms p)
370{
371    free(segments);
372}
373