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