|
|
1.1 root 1: /* $Header: ico.c,v 1.1 87/09/11 08:23:25 toddb Exp $ */
2: /***********************************************************
3: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
4: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
5:
6: All Rights Reserved
7:
8: Permission to use, copy, modify, and distribute this software and its
9: documentation for any purpose and without fee is hereby granted,
10: provided that the above copyright notice appear in all copies and that
11: both that copyright notice and this permission notice appear in
12: supporting documentation, and that the names of Digital or MIT not be
13: used in advertising or publicity pertaining to distribution of the
14: software without specific, written prior permission.
15:
16: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22: SOFTWARE.
23:
24: ******************************************************************/
25: /******************************************************************************
26: * Description
27: * Display a wire-frame rotating icosahedron, with hidden lines removed
28: *
29: * Arguments:
30: * -r display on root window instead of creating a new one
31: * =wxh+x+y X geometry for new window (default 600x600 centered)
32: * host:display X display on which to run
33: *****************************************************************************/
34:
35:
36:
37: #include <X11/Xlib.h>
38: #include <X11/Xatom.h>
39: #include <X11/Xutil.h>
40: #include <stdio.h>
41:
42:
43:
44: typedef struct
45: {
46: double x, y, z;
47: } Point3D;
48:
49: typedef double Transform3D[4][4];
50:
51:
52:
53: extern GC XCreateGC();
54: extern long time();
55: extern long random();
56:
57: Display *dpy;
58:
59: /******************************************************************************
60: * Description
61: * Main routine. Process command-line arguments, then bounce a bounding
62: * box inside the window. Call DrawIco() to redraw the icosahedron.
63: *****************************************************************************/
64:
65: main(argc, argv)
66: int argc;
67: char **argv;
68: {
69: char *display = NULL;
70: char *geom = NULL;
71: int useRoot = 0;
72: int fg, bg;
73: int invert = 0;
74: int dash = 0;
75:
76: Window win;
77: int winX, winY, winW, winH;
78: XSetWindowAttributes xswa;
79:
80: GC gc;
81:
82: int icoX, icoY;
83: int icoDeltaX, icoDeltaY;
84: int icoW, icoH;
85:
86: XEvent xev;
87: XGCValues xgcv;
88:
89: /* Process arguments: */
90:
91: while (*++argv)
92: {
93: if (**argv == '=')
94: geom = *argv;
95: else if (index(*argv, ':'))
96: display = *argv;
97: else if (!strcmp(*argv, "-r"))
98: useRoot = 1;
99: else if (!strcmp (*argv, "-d"))
100: dash = atoi(*++argv);
101: else if (!strcmp(*argv, "-i"))
102: invert = 1;
103: }
104:
105:
106: if (!(dpy= XOpenDisplay(display)))
107: {
108: perror("Cannot open display\n");
109: exit(-1);
110: }
111:
112: if (invert)
113: {
114: fg = BlackPixel(dpy, DefaultScreen(dpy));
115: bg = WhitePixel(dpy, DefaultScreen(dpy));
116: }
117: else
118: {
119: fg = WhitePixel(dpy, DefaultScreen(dpy));
120: bg = BlackPixel(dpy, DefaultScreen(dpy));
121: }
122:
123: /* Set up window parameters, create and map window if necessary: */
124:
125: if (useRoot)
126: {
127: win = DefaultRootWindow(dpy);
128: winX = 0;
129: winY = 0;
130: winW = DisplayWidth(dpy, DefaultScreen(dpy));
131: winH = DisplayHeight(dpy, DefaultScreen(dpy));
132: }
133: else
134: {
135: winW = 600;
136: winH = 600;
137: winX = (DisplayWidth(dpy, DefaultScreen(dpy)) - winW) >> 1;
138: winY = (DisplayHeight(dpy, DefaultScreen(dpy)) - winH) >> 1;
139: if (geom)
140: XParseGeometry(geom, &winX, &winY, &winW, &winH);
141:
142: xswa.event_mask = 0;
143: xswa.background_pixel = bg;
144: xswa.border_pixel = fg;
145: win = XCreateWindow(dpy, DefaultRootWindow(dpy),
146: winX, winY, winW, winH, 0,
147: DefaultDepth(dpy, DefaultScreen(dpy)),
148: InputOutput, DefaultVisual(dpy, DefaultScreen(dpy)),
149: CWEventMask | CWBackPixel | CWBorderPixel, &xswa);
150: XChangeProperty(dpy, win, XA_WM_NAME, XA_STRING, 8,
151: PropModeReplace, "Ico", 3);
152: XMapWindow(dpy, win);
153: }
154:
155:
156: /* Set up a graphics context: */
157:
158: gc = XCreateGC(dpy, win, 0, NULL);
159: XSetForeground(dpy, gc, fg);
160: XSetBackground(dpy, gc, bg);
161:
162: if (dash)
163: {
164: xgcv.line_style = LineDoubleDash;
165: xgcv.dashes = dash;
166: XChangeGC(dpy, gc, GCLineStyle | GCDashList, &xgcv);
167: }
168:
169: /* Get the initial position, size, and speed of the bounding-box: */
170:
171: icoW = icoH = 150;
172: srandom((int) time(0) % 231);
173: icoX = ((winW - icoW) * (random() & 0xFF)) >> 8;
174: icoY = ((winH - icoH) * (random() & 0xFF)) >> 8;
175: icoDeltaX = 13;
176: icoDeltaY = 9;
177:
178:
179: /* Bounce the box in the window: */
180:
181: for (;;)
182: {
183: int prevX;
184: int prevY;
185:
186: if (XPending(dpy))
187: XNextEvent(dpy, &xev);
188:
189: prevX = icoX;
190: prevY = icoY;
191:
192: icoX += icoDeltaX;
193: if (icoX < 0 || icoX + icoW > winW)
194: {
195: icoX -= (icoDeltaX << 1);
196: icoDeltaX = - icoDeltaX;
197: }
198: icoY += icoDeltaY;
199: if (icoY < 0 || icoY + icoH > winH)
200: {
201: icoY -= (icoDeltaY << 1);
202: icoDeltaY = - icoDeltaY;
203: }
204:
205: drawIco(win, gc, icoX, icoY, icoW, icoH, prevX, prevY);
206: }
207: }
208:
209:
210:
211: /******************************************************************************
212: * Description
213: * Undraw previous icosahedron (by erasing its bounding box).
214: * Rotate and draw the new icosahedron.
215: *
216: * Input
217: * win window on which to draw
218: * gc X11 graphics context to be used for drawing
219: * icoX, icoY position of upper left of bounding-box
220: * icoW, icoH size of bounding-box
221: * prevX, prevY position of previous bounding-box
222: *****************************************************************************/
223:
224: drawIco(win, gc, icoX, icoY, icoW, icoH, prevX, prevY)
225: Window win;
226: GC gc;
227: int icoX, icoY, icoW, icoH;
228: int prevX, prevY;
229: {
230: static int initialized = 0;
231: static Point3D v[] = /* icosahedron vertices */
232: {
233: { 0.00000000, 0.00000000, -0.95105650},
234: { 0.00000000, 0.85065080, -0.42532537},
235: { 0.80901698, 0.26286556, -0.42532537},
236: { 0.50000000, -0.68819095, -0.42532537},
237: {-0.50000000, -0.68819095, -0.42532537},
238: {-0.80901698, 0.26286556, -0.42532537},
239: { 0.50000000, 0.68819095, 0.42532537},
240: { 0.80901698, -0.26286556, 0.42532537},
241: { 0.00000000, -0.85065080, 0.42532537},
242: {-0.80901698, -0.26286556, 0.42532537},
243: {-0.50000000, 0.68819095, 0.42532537},
244: { 0.00000000, 0.00000000, 0.95105650}
245: };
246: static int f[] = /* icosahedron faces (indices in v) */
247: {
248: 0, 2, 1,
249: 0, 3, 2,
250: 0, 4, 3,
251: 0, 5, 4,
252: 0, 1, 5,
253: 1, 6, 10,
254: 1, 2, 6,
255: 2, 7, 6,
256: 2, 3, 7,
257: 3, 8, 7,
258: 3, 4, 8,
259: 4, 9, 8,
260: 4, 5, 9,
261: 5, 10, 9,
262: 5, 1, 10,
263: 10, 6, 11,
264: 6, 7, 11,
265: 7, 8, 11,
266: 8, 9, 11,
267: 9, 10, 11
268: };
269: # define NV (sizeof(v) / sizeof(v[0]))
270: # define NF (sizeof(f) / (3 * sizeof(f[0])))
271:
272: static Transform3D xform;
273: static Point3D xv[2][NV];
274: static int buffer;
275: register int p0;
276: register int p1;
277: register int p2;
278: register XPoint *pv2;
279: XSegment *pe;
280: char drawn[NV][NV];
281: register Point3D *pxv;
282: static double wo2, ho2;
283: XPoint v2[NV];
284: XSegment edges[30];
285: register int i;
286: register int *pf;
287:
288:
289: /* Set up points, transforms, etc.: */
290:
291: if (!initialized)
292: {
293: Transform3D r1;
294: Transform3D r2;
295:
296: FormatRotateMat('x', 5 * 3.1416 / 180.0, r1);
297: FormatRotateMat('y', 5 * 3.1416 / 180.0, r2);
298: ConcatMat(r1, r2, xform);
299:
300: bcopy((char *) v, (char *) xv[0], NV * sizeof(Point3D));
301: buffer = 0;
302:
303: wo2 = icoW / 2.0;
304: ho2 = icoH / 2.0;
305:
306: initialized = 1;
307: }
308:
309:
310: /* Switch double-buffer and rotate vertices: */
311:
312: buffer = !buffer;
313: PartialNonHomTransform(NV, xform, xv[!buffer], xv[buffer]);
314:
315:
316: /* Convert 3D coordinates to 2D window coordinates: */
317:
318: pxv = xv[buffer];
319: pv2 = v2;
320: for (i = NV - 1; i >= 0; --i)
321: {
322: pv2->x = (int) ((pxv->x + 1.0) * wo2) + icoX;
323: pv2->y = (int) ((pxv->y + 1.0) * ho2) + icoY;
324: ++pxv;
325: ++pv2;
326: }
327:
328:
329: /* Accumulate edges to be drawn, eliminating duplicates for speed: */
330:
331: pxv = xv[buffer];
332: pv2 = v2;
333: pf = f;
334: pe = edges;
335: bzero(drawn, sizeof(drawn));
336: for (i = NF - 1; i >= 0; --i)
337: {
338: p0 = *pf++;
339: p1 = *pf++;
340: p2 = *pf++;
341:
342: /* If facet faces away from viewer, don't consider it: */
343: if (pxv[p0].z + pxv[p1].z + pxv[p2].z < 0.0)
344: continue;
345:
346: if (!drawn[p0][p1])
347: {
348: drawn[p0][p1] = 1;
349: drawn[p1][p0] = 1;
350: pe->x1 = pv2[p0].x;
351: pe->y1 = pv2[p0].y;
352: pe->x2 = pv2[p1].x;
353: pe->y2 = pv2[p1].y;
354: ++pe;
355: }
356: if (!drawn[p1][p2])
357: {
358: drawn[p1][p2] = 1;
359: drawn[p2][p1] = 1;
360: pe->x1 = pv2[p1].x;
361: pe->y1 = pv2[p1].y;
362: pe->x2 = pv2[p2].x;
363: pe->y2 = pv2[p2].y;
364: ++pe;
365: }
366: if (!drawn[p2][p0])
367: {
368: drawn[p2][p0] = 1;
369: drawn[p0][p2] = 1;
370: pe->x1 = pv2[p2].x;
371: pe->y1 = pv2[p2].y;
372: pe->x2 = pv2[p0].x;
373: pe->y2 = pv2[p0].y;
374: ++pe;
375: }
376: }
377:
378:
379: /* Erase previous, draw current icosahedrons; sync for smoothness. */
380:
381: XClearArea(dpy, win, prevX, prevY, icoW + 1, icoH + 1, 0);
382: XDrawSegments(dpy, win, gc, edges, pe - edges);
383: XSync(dpy, 0);
384: }
385:
386:
387:
388: /******************************************************************************
389: * Description
390: * Concatenate two 4-by-4 transformation matrices.
391: *
392: * Input
393: * l multiplicand (left operand)
394: * r multiplier (right operand)
395: *
396: * Output
397: * *m Result matrix
398: *****************************************************************************/
399:
400: ConcatMat(l, r, m)
401: register Transform3D l;
402: register Transform3D r;
403: register Transform3D m;
404: {
405: register int i;
406: register int j;
407: register int k;
408:
409: for (i = 0; i < 4; ++i)
410: for (j = 0; j < 4; ++j)
411: m[i][j] = l[i][0] * r[0][j]
412: + l[i][1] * r[1][j]
413: + l[i][2] * r[2][j]
414: + l[i][3] * r[3][j];
415: }
416:
417:
418:
419: /******************************************************************************
420: * Description
421: * Format a matrix that will perform a rotation transformation
422: * about the specified axis. The rotation angle is measured
423: * counterclockwise about the specified axis when looking
424: * at the origin from the positive axis.
425: *
426: * Input
427: * axis Axis ('x', 'y', 'z') about which to perform rotation
428: * angle Angle (in radians) of rotation
429: * A Pointer to rotation matrix
430: *
431: * Output
432: * *m Formatted rotation matrix
433: *****************************************************************************/
434:
435: FormatRotateMat(axis, angle, m)
436: char axis;
437: double angle;
438: register Transform3D m;
439: {
440: double s, c;
441: double sin(), cos();
442:
443: IdentMat(m);
444:
445: s = sin(angle);
446: c = cos(angle);
447:
448: switch(axis)
449: {
450: case 'x':
451: m[1][1] = m[2][2] = c;
452: m[1][2] = s;
453: m[2][1] = -s;
454: break;
455: case 'y':
456: m[0][0] = m[2][2] = c;
457: m[2][0] = s;
458: m[0][2] = -s;
459: break;
460: case 'z':
461: m[0][0] = m[1][1] = c;
462: m[0][1] = s;
463: m[1][0] = -s;
464: break;
465: }
466: }
467:
468:
469:
470: /******************************************************************************
471: * Description
472: * Format a 4x4 identity matrix.
473: *
474: * Output
475: * *m Formatted identity matrix
476: *****************************************************************************/
477:
478: IdentMat(m)
479: register Transform3D m;
480: {
481: register int i;
482: register int j;
483:
484: for (i = 3; i >= 0; --i)
485: {
486: for (j = 3; j >= 0; --j)
487: m[i][j] = 0.0;
488: m[i][i] = 1.0;
489: }
490: }
491:
492:
493:
494: /******************************************************************************
495: * Description
496: * Perform a partial transform on non-homogeneous points.
497: * Given an array of non-homogeneous (3-coordinate) input points,
498: * this routine multiplies them by the 3-by-3 upper left submatrix
499: * of a standard 4-by-4 transform matrix. The resulting non-homogeneous
500: * points are returned.
501: *
502: * Input
503: * n number of points to transform
504: * m 4-by-4 transform matrix
505: * in array of non-homogeneous input points
506: *
507: * Output
508: * *out array of transformed non-homogeneous output points
509: *****************************************************************************/
510:
511: PartialNonHomTransform(n, m, in, out)
512: int n;
513: register Transform3D m;
514: register Point3D *in;
515: register Point3D *out;
516: {
517: for (; n > 0; --n, ++in, ++out)
518: {
519: out->x = in->x * m[0][0] + in->y * m[1][0] + in->z * m[2][0];
520: out->y = in->x * m[0][1] + in->y * m[1][1] + in->z * m[2][1];
521: out->z = in->x * m[0][2] + in->y * m[1][2] + in->z * m[2][2];
522: }
523: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.