1 #include <X11/X.h>
2 #include <X11/Xlib.h>
3 #include <math.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include "lmath.h"
8 #include "trippy.h"
9
10 /*
11 Data on various polyhedra is available at
12 http://netlib.att.com/netlib/polyhedra/index.html
13 For the icosahedron, the twelve vertices are:
14
15 (+- 1, 0, +-t), (0, +-t, +-1), and (+-t, +-1, 0)
16
17 where t = (sqrt(5)-1)/2, the golden ratio.
18 */
19
20 typedef struct vt { /* Structure for individual vertices */
21 int lx,ly,lz; /* Local coordinates of vertex */
22 float wx,wy,wz; /* World coordinates of vertex */
23 int sx,sy,sz; /* Screen coordinates of vertex */
24 } vertex_type;
25
26 typedef struct _sha
27 {
28 vertex_type* vertices;
29 vertex_type** faces;
30 int maxVis, numVert, numSides, numEdges;
31 void (*draw_func)(int,vertex_type**,int);
32 } SHAPE;
33
34 static float matrix[16]; /* Master transformation matrix */
35 static void matmult(float res[16],float mat1[16],float mat2[16]);
36 #define matcopy(x,y) memcpy(x,y,sizeof(float)*16)
37 static void init_matrix();
38 static void scale(float);
39 static void rotate(float,float,float);
40
41 /* Transformation functions: */
42
43 void
init_matrix()44 init_matrix()
45 {
46 /* Set the master matrix to | 1 0 0 0 |
47 * | 0 1 0 0 |
48 * | 0 0 1 0 |
49 * | 0 0 0 1 |
50 */
51
52 matrix[1]=matrix[2]=matrix[3]=matrix[4]=
53 matrix[6]=matrix[7]=matrix[8]=matrix[9]=
54 matrix[11]=matrix[12]=matrix[13]=matrix[14] = 0.0;
55 matrix[0]=matrix[5]=matrix[10]=matrix[15]=1.0;
56 }
57
58 void
scale(float sf)59 scale(float sf)
60 {
61 /*
62 * Multiply the master matrix by the scaling factor (sf)
63 *
64 *
65 * Note: assuming that this funciton will be run right after
66 * the init function, we could reduce the code to:
67 * matrix[0]=matrix[5]=matrix[10]=sf;
68 *
69 * since that is the only change.
70 */
71 float mat[16];
72 float smat[16];
73
74 memset(smat,0,16*sizeof(float));
75 smat[0]=smat[5]=smat[10]=sf;
76 smat[15]=1;
77
78 matmult(mat,smat,matrix);
79 matcopy(matrix,mat);
80 }
81
82 void
rotate(float ax,float ay,float az)83 rotate(float ax, float ay, float az)
84 {
85 float mx[16];
86 float mat[16];
87
88 float cosx= cos(ax);
89 float sinx= sin(ax);
90 float cosy= cos(ay);
91 float siny= sin(ay);
92 float cosz= cos(az);
93 float sinz= sin(az);
94
95 /*
96 * This is 3 matrix multiplies worked out into one.
97 * fun fun math (grin)
98 */
99 mx[0]= (cosy*cosz);
100 mx[1]= (cosy*sinz);
101 mx[2]= -siny;
102 mx[4]= ((sinx*siny*cosz)-(cosx*sinz));
103 mx[5]= ((sinx*siny*sinz)+(cosx*cosz));
104 mx[6]= (sinx*cosy);
105 mx[8]= ((cosx*siny*cosz)+(sinx*sinz));
106 mx[9]= ((cosx*siny*sinz)-(sinx*cosz));
107 mx[10]= (cosx*cosy);
108 mx[3]= mx[7]= mx[11]= mx[12]= mx[13]= mx[14]=0;
109 mx[15]=1;
110
111 matmult(mat,matrix,mx);
112 matcopy(matrix,mat);
113 }
114
115 void
translate(int xt,int yt,int zt)116 translate(int xt,int yt,int zt)
117 {
118 /*
119 * here we move the shape into position
120 */
121 float tmat[16];
122 float mat[16];
123
124 memset(tmat,0,16*sizeof(float));
125 tmat[0]=tmat[5]=tmat[10]=tmat[15]=1;
126 tmat[12]=xt; tmat[13]=yt; tmat[14]=zt;
127
128 matmult(mat,matrix,tmat);
129 matcopy(matrix,mat);
130 }
131
132 void
transform(int numvert,vertex_type * vertices)133 transform(int numvert, vertex_type *vertices)
134 {
135 /*
136 * and now we run our shape's coordinates through the matrix
137 */
138 int v;
139 vertex_type *vptr=vertices;
140 for (v=0; v<numvert; v++)
141 {
142 vptr->wx=(vptr->lx*matrix[0] + vptr->ly*matrix[4] +
143 vptr->lz*matrix[8] + matrix[12]);
144 vptr->wy=(vptr->lx*matrix[1] + vptr->ly*matrix[5] +
145 vptr->lz*matrix[9] + matrix[13]);
146 vptr->wz=(vptr->lx*matrix[2] + vptr->ly*matrix[6] +
147 vptr->lz*matrix[10]+ matrix[14]);
148 vptr++;
149 }
150 }
151
152 void
project(float distance,int numvert,vertex_type * vertices)153 project(float distance, int numvert, vertex_type* vertices)
154 {
155 /* Project shape onto screen */
156 int v;
157 vertex_type *vptr=vertices;
158
159 /* Loop though vertices: */
160 for (v=0; v<numvert; v++,vptr++)
161 {
162 float fx,fy;
163
164 /* Divide world x & y coords by z coords: */
165 /* if vptr->wz = 0, something is not right with the world */
166 fx= (distance/vptr->wz);
167 vptr->sx = fx*vptr->wx;
168 fy= (distance/vptr->wz);
169 vptr->sy = fy*vptr->wy;
170 }
171 }
172
173 void
matmult(float result[16],float mat1[16],float mat2[16])174 matmult(float result[16],float mat1[16], float mat2[16])
175 {
176 int i,j;
177
178 /* Multiply matrix MAT1 by matrix MAT2,
179 * returning the result in RESULT
180 */
181 float *res = result;
182 for (i=0; i<4; i++)
183 {
184 int i4 = i*4;
185 for (j=0; j<4; j++)
186 {
187 *res = mat1[i4] * mat2[j];
188 *res += mat1[i4+1] * mat2[4+j];
189 *res += mat1[i4+2] * mat2[8+j];
190 *res += mat1[i4+3] * mat2[12+j];
191 res++;
192 }
193 }
194 return;
195 }
196
197 void
drawTriFace(int winno,vertex_type ** vertices,int clr)198 drawTriFace(int winno, vertex_type **vertices,int clr)
199 {
200 int i;
201 XPoint pts[3];
202 XSegment *segs;
203
204 long x1= vertices[0]->sx;
205 long y1= vertices[0]->sy;
206 long x2= vertices[1]->sx;
207 long y2= vertices[1]->sy;
208 long x3= vertices[2]->sx;
209 long y3= vertices[2]->sy;
210
211 long dx1 = ((x3-x1)<<8) /options.number;
212 long dy1 = ((y3-y1)<<8) /options.number;
213 long dx2 = ((x3-x2)<<8) /options.number;
214 long dy2 = ((y3-y2)<<8) /options.number;
215 long XORIGIN= CX[winno]>>1;
216 long YORIGIN= CY[winno]>>1;
217
218 segs = (XSegment *)malloc(sizeof(XSegment)*(options.number+3));
219
220 /* center the shape on the window */
221 x1+=XORIGIN; x2+=XORIGIN; x3+=XORIGIN;
222 y1+=YORIGIN; y2+=YORIGIN; y3+=YORIGIN;
223
224 pts[0].x=x1; pts[0].y=y1;
225 pts[1].x=x2; pts[1].y=y2;
226 pts[2].x=x3; pts[2].y=y3;
227
228 /*
229 XFillPolygon(display,window[winno],color_gcs[clr],pts,3,
230 Convex,CoordModeOrigin);
231 */
232 /* XDrawLine(display,window[winno],color_gcs[clr],x1,y1,x3,y3); */
233 segs[0].x1 = x1;
234 segs[0].x2 = x3;
235 segs[0].y1 = y1;
236 segs[0].y2 = y3;
237
238 /* XDrawLine(display,window[winno],color_gcs[clr],x2,y2,x3,y3); */
239 segs[1].x1 = x2;
240 segs[1].x2 = x3;
241 segs[1].y1 = y2;
242 segs[1].y2 = y3;
243
244 x1<<=8; y1<<=8; x2<<=8; y2<<=8;
245 for(i=0;i<=options.number;i++)
246 {
247 /* XDrawLine(display,window[winno],color_gcs[clr],x1>>8,y1>>8,
248 x2>>8,y2>>8);
249 */
250 segs[i+2].x1 = x1>>8;
251 segs[i+2].x2 = x2>>8;
252 segs[i+2].y1 = y1>>8;
253 segs[i+2].y2 = y2>>8;
254
255 x1+=dx1; y1+=dy1;
256 x2+=dx2; y2+=dy2;
257 }
258
259 XDrawSegments(display,window[winno],color_gcs[clr],segs,options.number+3);
260
261 free(segs);
262
263 return;
264 }
265
266 void
drawSquareFace(int winno,vertex_type ** vertices,int clr)267 drawSquareFace(int winno,vertex_type **vertices,int clr)
268 {
269 int i;
270 XSegment *segs;
271 long x1= vertices[0]->sx;
272 long y1= vertices[0]->sy;
273 long x2= vertices[3]->sx;
274 long y2= vertices[3]->sy;
275 long x3,x4,y3,y4;
276 long dx1 = (((x3=vertices[1]->sx)-x1)<<8) /options.number;
277 long dy1 = (((y3=vertices[1]->sy)-y1)<<8) /options.number;
278 long dx2 = (((x4=vertices[2]->sx)-x2)<<8) /options.number;
279 long dy2 = (((y4=vertices[2]->sy)-y2)<<8) /options.number;
280 long XORIGIN= CX[winno]>>1;
281 long YORIGIN= CY[winno]>>1;
282
283 segs = (XSegment *)malloc(sizeof(XSegment)*(options.number+3));
284
285 x1+=XORIGIN; x2+=XORIGIN; x3+=XORIGIN; x4+=XORIGIN;
286 y1+=YORIGIN; y2+=YORIGIN; y3+=YORIGIN; y4+=YORIGIN;
287
288 /* XDrawLine(display,window[winno],color_gcs[clr],x1,y1,x3,y3); */
289 segs[0].x1 = x1;
290 segs[0].x2 = x3;
291 segs[0].y1 = y1;
292 segs[0].y2 = y3;
293
294 /* XDrawLine(display,window[winno],color_gcs[clr],x2,y2,x4,y4); */
295 segs[1].x1 = x2;
296 segs[1].x2 = x4;
297 segs[1].y1 = y2;
298 segs[1].y2 = y4;
299
300 x1<<=8; y1<<=8; x2<<=8; y2<<=8;
301 for(i=0;i<=options.number;i++)
302 {
303 segs[i+2].x1 = x1>>8;
304 segs[i+2].x2 = x2>>8;
305 segs[i+2].y1 = y1>>8;
306 segs[i+2].y2 = y2>>8;
307
308 /* XDrawLine(display,window[winno],color_gcs[clr],x1>>8,y1>>8,
309 x2>>8,y2>>8);
310 */
311 x1+=dx1; y1+=dy1;
312 x2+=dx2; y2+=dy2;
313 }
314
315 XDrawSegments(display,window[winno],color_gcs[clr],segs,options.number+3);
316
317 free(segs);
318 }
319
320 /* Returns 0 if POLYGON is visible, -1 if not.
321 * POLYGON must be part of a convex polyhedron
322 */
323 #define backface(verts) (((verts[1]->sx-verts[0]->sx)*\
324 (verts[2]->sy-verts[0]->sy)-\
325 (verts[1]->sy-verts[0]->sy)*\
326 (verts[2]->sx-verts[0]->sx))>=0)
327
328 void
draw_shape(int winno,int clr,SHAPE * shape)329 draw_shape(int winno, int clr, SHAPE *shape)
330 {
331 int i;
332 int j=0;
333 vertex_type ** faces;
334 int edges;
335
336 edges = shape->numEdges;
337 faces = shape->faces;
338 for(i=0; i<shape->numSides; i++)
339 {
340 if (backface(faces))
341 {
342 shape->draw_func(winno,faces,
343 (clr==1)?0:(numcolors*(i%5)/6)+5);
344 j++;
345 }
346 if(j>shape->maxVis)
347 break;
348 faces += edges;
349 }
350 }
351
352 /* and now, define the shapes */
353
354 vertex_type oct_vertices[]=
355 {
356 {20, 0, 0,
357 0, 0, 0,
358 0, 0, 0},
359 {-20, 0, 0,
360 0, 0, 0,
361 0, 0, 0},
362 {0, 20, 0,
363 0, 0, 0,
364 0, 0, 0},
365 {0,-20,0,
366 0, 0, 0,
367 0, 0, 0},
368 {0, 0,20,
369 0, 0, 0,
370 0, 0, 0},
371 {0, 0,-20,
372 0, 0, 0,
373 0, 0, 0},
374 };
375
376 vertex_type *oct_faces[]=
377 {
378 &oct_vertices[0],&oct_vertices[4],&oct_vertices[2],
379 &oct_vertices[1],&oct_vertices[2],&oct_vertices[4],
380 &oct_vertices[0],&oct_vertices[3],&oct_vertices[4],
381 &oct_vertices[1],&oct_vertices[4],&oct_vertices[3],
382 &oct_vertices[0],&oct_vertices[2],&oct_vertices[5],
383 &oct_vertices[1],&oct_vertices[5],&oct_vertices[2],
384 &oct_vertices[0],&oct_vertices[5],&oct_vertices[3],
385 &oct_vertices[1],&oct_vertices[3],&oct_vertices[5]
386 };
387
388 SHAPE octo=
389 {
390 oct_vertices,oct_faces,4,6,8,3,drawTriFace
391 };
392
393
394 vertex_type tet_vertices[]=
395 {
396 {10, 10, 10,
397 0, 0, 0,
398 0, 0, 0},
399 {10,-10,-10,
400 0, 0, 0,
401 0, 0, 0},
402 {-10,10,-10,
403 0, 0, 0,
404 0, 0, 0},
405 {-10,-10,10,
406 0, 0,0,
407 0, 0,0},
408 };
409
410 vertex_type *tet_faces[]=
411 {
412 &tet_vertices[0], &tet_vertices[1],&tet_vertices[3],
413 &tet_vertices[2], &tet_vertices[1],&tet_vertices[0],
414 &tet_vertices[3], &tet_vertices[2],&tet_vertices[0],
415 &tet_vertices[1], &tet_vertices[2],&tet_vertices[3]
416 };
417
418 SHAPE tetra=
419 {
420 tet_vertices,tet_faces,3,4,4,3,drawTriFace
421 };
422
423 vertex_type cube_vertices[]=
424 { /* Vertices for cube */
425 {-10,-10,10,
426 0, 0, 0,
427 0, 0, 0},
428 {10,-10,10,
429 0, 0, 0,
430 0, 0, 0},
431 {10,10,10,
432 0, 0, 0,
433 0, 0, 0},
434 {-10,10,10,
435 0, 0, 0,
436 0, 0, 0},
437 {-10,-10,-10,
438 0, 0, 0,
439 0, 0, 0},
440 {10,-10,-10,
441 0, 0, 0,
442 0, 0, 0},
443 {10,10,-10,
444 0, 0, 0,
445 0, 0, 0},
446 {-10,10,-10,
447 0,0,0,
448 0,0,0
449 }
450 };
451
452 vertex_type *cube_faces[24] =
453 {
454 &cube_vertices[0],&cube_vertices[1],&cube_vertices[5],&cube_vertices[4],
455 &cube_vertices[5],&cube_vertices[6],&cube_vertices[7],&cube_vertices[4],
456 &cube_vertices[2],&cube_vertices[6],&cube_vertices[5],&cube_vertices[1],
457 &cube_vertices[6],&cube_vertices[2],&cube_vertices[3],&cube_vertices[7],
458 &cube_vertices[2],&cube_vertices[1],&cube_vertices[0],&cube_vertices[3],
459 &cube_vertices[4],&cube_vertices[7],&cube_vertices[3],&cube_vertices[0]
460 };
461
462 SHAPE cubik=
463 {
464 cube_vertices,cube_faces,4,8,6,4,drawSquareFace
465 };
466
467 #define NUMSTEPS 124 /* twelve step program to change */
468
469 void
morph(int winno,SHAPE * source,SHAPE * dest)470 morph(int winno, SHAPE* source, SHAPE* dest)
471 {
472 SHAPE temp;
473 int i,step;
474 float *dx , *dy, *dz;
475 float *newx, *newy, *newz;
476
477 fprintf (stderr,"Morphing from %d to %d\n",source->numVert,dest->numVert);
478
479 if(source->numVert > dest->numVert)
480 {
481 temp.numVert=source->numVert;
482 temp.numSides=source->numSides;
483 temp.numEdges=source->numEdges;
484 temp.maxVis=source->maxVis;
485 }
486 else
487 {
488 temp.numVert=dest->numVert;
489 temp.numSides=dest->numSides;
490 temp.numEdges=dest->numEdges;
491 temp.maxVis=dest->maxVis;
492 }
493
494 dx=(float*)malloc(sizeof(float)*temp.numVert);
495 dy=(float*)malloc(sizeof(float)*temp.numVert);
496 dz=(float*)malloc(sizeof(float)*temp.numVert);
497 newx=(float*)calloc(temp.numVert,sizeof(float));
498 newy=(float*)calloc(temp.numVert,sizeof(float));
499 newz=(float*)calloc(temp.numVert,sizeof(float));
500 temp.vertices=(vertex_type*)malloc(sizeof(vertex_type)*temp.numVert);
501 temp.faces=(vertex_type**)malloc(sizeof(vertex_type*)*temp.numSides*
502 temp.numEdges);
503
504 if(source->numVert > dest->numVert)
505 {
506
507 memcpy(temp.vertices,source->vertices,
508 sizeof(vertex_type)*source->numVert);
509 for(i=0;i<(source->numSides*source->numEdges);i++)
510 {
511 /* wheee.. fun with pointer math ... but will it work everywhere? */
512 /* eh... what the hell, it works under Linux/GCC */
513 int base=(int)&(source->vertices[0]);
514 int facenum =(int) (source->faces[i]);
515 int sidenum= (facenum-base)/(sizeof(vertex_type));
516 temp.faces[i]= &temp.vertices[sidenum];
517 }
518 for(i=0;i<dest->numVert;i++)
519 {
520 dx[i]=(float)(dest->vertices[i].lx-source->vertices[i].lx)/NUMSTEPS;
521 dy[i]=(float)(dest->vertices[i].ly-source->vertices[i].ly)/NUMSTEPS;
522 dz[i]=(float)(dest->vertices[i].lz-source->vertices[i].lz)/NUMSTEPS;
523 newx[i]=source->vertices[i].lx;
524 newy[i]=source->vertices[i].ly;
525 newz[i]=source->vertices[i].lz;
526 }
527 for(;i<temp.numVert;i++)
528 {
529 dx[i]=(float)(-source->vertices[i].lx)/NUMSTEPS;
530 dy[i]=(float)(-source->vertices[i].ly)/NUMSTEPS;
531 dz[i]=(float)(-source->vertices[i].lz)/NUMSTEPS;
532 newx[i]=source->vertices[i].lx;
533 newy[i]=source->vertices[i].ly;
534 newz[i]=source->vertices[i].lz;
535 }
536 }
537 else
538 {
539 memcpy(temp.vertices,dest->vertices,
540 sizeof(vertex_type)*dest->numVert);
541 for(i=0;i<(dest->numSides*dest->numEdges);i++)
542 {
543 /* wheee.. fun with pointer math ... but will it work everywhere? */
544 int base=(int) &(dest->vertices[0]);
545 int facenum =(int) (dest->faces[i]);
546 int sidenum = (facenum-base)/sizeof(vertex_type);
547 /* fprintf(stderr,"Sidenum %d = %d\t",i,sidenum); */
548 temp.faces[i]= &temp.vertices[sidenum];
549 }
550 for(i=0;i<source->numVert;i++)
551 {
552 dx[i]=(float)(dest->vertices[i].lx-source->vertices[i].lx)/NUMSTEPS;
553 dy[i]=(float)(dest->vertices[i].ly-source->vertices[i].ly)/NUMSTEPS;
554 dz[i]=(float)(dest->vertices[i].lz-source->vertices[i].lz)/NUMSTEPS;
555 newx[i]=source->vertices[i].lx;
556 newy[i]=source->vertices[i].ly;
557 newz[i]=source->vertices[i].lz;
558
559 }
560 for(;i<temp.numVert;i++)
561 {
562 dx[i]=(float)(dest->vertices[i].lx)/NUMSTEPS;
563 dy[i]=(float)(dest->vertices[i].ly)/NUMSTEPS;
564 dz[i]=(float)(dest->vertices[i].lz)/NUMSTEPS;
565 newx[i]=0;
566 newy[i]=0;
567 newz[i]=0;
568 }
569 }
570
571 if(source->draw_func==dest->draw_func)
572 {
573 temp.draw_func=source->draw_func;
574 }
575 else
576 {
577 temp.draw_func=drawSquareFace; /*this func should deal with everything */
578 }
579 /* ok, now the shape is defined */
580
581 for(step=0;step<NUMSTEPS;step++)
582 {
583 for(i=0;i<temp.numVert;i++)
584 {
585 newx[i]+= dx[i];
586 temp.vertices[i].lx = (int)newx[i];
587 newy[i]+= dy[i];
588 temp.vertices[i].ly = (int)newy[i];
589 newz[i]+= dz[i];
590 temp.vertices[i].lz = (int)newz[i];
591 }
592
593 transform(temp.numVert, temp.vertices);
594 draw_shape(winno,1,&temp); /* clear */
595 project(400,temp.numVert,temp.vertices); /* calculate */
596 draw_shape(winno,0,&temp); /* and draw */
597 }
598
599
600 /* all done, clean up */
601 draw_shape(winno,1,&temp); /* clear */
602 free(newx);
603 free(newy);
604 free(newz);
605 free(dx);
606 free(dy);
607 free(dz);
608 free(temp.faces);
609 free(temp.vertices);
610 return;
611 }
612
613 void
exit_maxh()614 exit_maxh()
615 {
616 return;
617 }
618
619 void
exit_cube()620 exit_cube()
621 {
622 return;
623 }
624
625 void
exit_oct()626 exit_oct()
627 {
628 return;
629 }
630
631 void
exit_tet()632 exit_tet()
633 {
634 return;
635 }
636
637 void
exit_shape()638 exit_shape()
639 {
640 return;
641 }
642
643 void
rotate_shape(int winno)644 rotate_shape(int winno)
645 {
646 static float xangle = 0.0, yangle= 0.0, zangle = 0.0;
647 static float xrot = 0.0174532, yrot=0.0174532, zrot=0.0174532;
648 static int xloc=0, yloc=0;
649 static int dist=400, distrot=0;
650 static char *init=0;
651
652 static SHAPE** shape;
653
654 if(!init)
655 {
656 shape = (SHAPE **) malloc(options.windows*sizeof(SHAPE*));
657 init = (char*)calloc(options.windows,sizeof(char));
658 }
659
660 if(!init[winno])
661 {
662 switch(options.mode)
663 {
664 case tet:
665 shape[winno]=&tetra; break;
666 case oct:
667 shape[winno]=&octo; break;
668 case cube:
669 shape[winno]=&cubik; break;
670 case rot_shape:
671 default:
672 shape[winno]=&cubik; break;
673 }
674
675 init[winno]=1;
676 }
677
678 init_matrix();
679 scale(1.5);
680 rotate(xangle,yangle,zangle);
681 xangle += xrot;
682 yangle += yrot;
683 zangle += zrot;
684 dist += distrot;
685 translate(xloc,yloc,50);
686
687 transform(shape[winno]->numVert, shape[winno]->vertices);
688
689 draw_shape(winno,1,shape[winno]); /* clear */
690
691 project((options.mode==maxh)?(max(CX[winno],CY[winno])*2):dist,
692 shape[winno]->numVert,shape[winno]->vertices); /* calculate */
693
694 draw_shape(winno,0,shape[winno]); /* and draw */
695
696 if(rndm(500)==0) xrot*=-1;
697 if(rndm(500)==0) yrot*=-1;
698 if(rndm(500)==0) zrot*=-1;
699 /* if(rndm(500)==0) distrot+=(rndm(3)-1); */
700 if(rndm(100)==0 && options.mode==rot_shape)
701 {
702 if(shape[winno]== &octo)
703 {
704 draw_shape(winno,1,shape[winno]); /* clear */
705 shape[winno]=(rndm(10)>4?&cubik:&tetra);
706 morph(winno,&octo,shape[winno]);
707 }
708 else if (shape[winno]== &cubik)
709 {
710 draw_shape(winno,1,shape[winno]); /* clear */
711 shape[winno]=(rndm(10)>4?&octo:&tetra);
712 morph(winno,&cubik,shape[winno]);
713 }
714 else if (shape[winno] == &tetra)
715 {
716 draw_shape(winno,1,shape[winno]); /* clear */
717 shape[winno]=(rndm(10)>4?&octo:&cubik);
718 morph(winno,&tetra,shape[winno]);
719 }
720 else
721 {
722 fprintf(stderr,"Whoa! Bizarre shape.\n");
723 exit(0);
724 }
725 }
726 return;
727 }
728