1 /*
2  *  Frame.c defines the bouncing shapes (qix,bozo, bez, etc) routines
3  *  by Jer Johnson (jer@gweep.net)
4  *
5  */
6 
7 #include <math.h>
8 #include <X11/X.h>
9 #include <X11/Xlib.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include "trippy.h"
13 #include "lmath.h"
14 
15 struct pt
16 {
17   int x, y;
18   int dx,dy;
19   int pixel;
20   struct pt *next, *prev;
21 };
22 
23 typedef struct pt PT;
24 
25 struct PTList
26 {
27   int size;
28   PT *next, *prev;
29 };
30 typedef struct PTList ptList;
31 
32 ptList *head1,*head2,*head3,*head4;
33 
34 int HCV;
35 static int inited=0;
36 static XPoint *make_bozo(int,int,int,int,int,int,int,int);
37 
38 void
add(ptList * here,int init,int winno)39 add(ptList *here,int init,int winno)
40 {
41   PT *point;
42 
43   point=(PT *)malloc(sizeof(PT));
44 
45   if(init)  /* if we need to create a point, do it here */
46   {
47     point->x=rndm(CX[winno]);
48     point->y=rndm(CY[winno]);
49     point->dx=1;
50     point->dy=1;
51     point->pixel=rndm(numcolors-1)+1;
52   }
53   else     /* otherwise, just move an existing point */
54   {
55     int radius = math_dist(head2[winno].next->x,head2[winno].next->y,
56 			   head1[winno].next->x,head1[winno].next->y);
57     point->x=here->next->x+here->next->dx;
58     point->y=here->next->y+here->next->dy;
59     point->dx=here->next->dx;
60     point->dy=here->next->dy;
61     point->pixel=(here->next->pixel+HCV)%numcolors;
62     if (!rndm((long)(1000)))
63       point->pixel=rndm(numcolors-1)+1;
64     if((point->x<0)|| ((options.mode==circ)&&(point->x<radius)))
65     {
66       point->dx=rndm(7);
67       point->x+=point->dx;
68     }
69     else if((point->x>CX[winno])||
70 	    ((options.mode==circ)&&(CX[winno]-point->x<radius)))
71     {
72       point->dx= -rndm(7);
73       point->x+=point->dx;
74     }
75     if((point->y<0)|| ((options.mode==circ)&&(point->y<radius)))
76     {
77       point->dy=rndm(7);
78       point->y+=point->dy;
79     }
80     else if((point->y>CY[winno])||
81 	    ((options.mode==circ)&&(CY[winno]-point->y<radius)))
82     {
83       point->dy= -rndm(7);
84       point->y+=point->dy;
85     }
86   }
87 
88   if(here->prev==NULL)
89     here->prev=point;
90   if(here->next==NULL)
91     here->next=point;
92   else
93   {
94     here->next->prev=point;
95     point->next=here->next;
96     point->prev=here->prev;
97     here->next=point;
98   }
99   here->size++;
100 }
101 
delete1(ptList * here)102 void delete1(ptList *here)
103 {
104   PT *temp=here->prev->prev;
105   here->next->prev=temp;
106   temp->next=here->next;
107 
108   free(here->prev);
109   here->prev=temp;
110 
111   here->size--;
112 }
113 
114 void
exit_frame(int winno)115 exit_frame(int winno)
116 {
117   int i;
118 
119   i = winno;
120   fprintf(stderr,"Exiting frame\n");
121 
122 /*  for(i=0;i<options.windows;i++) */
123   {
124     while(head1[i].size>0)
125       delete1(&head1[i]);
126     while(head2[i].size>0)
127       delete1(&head2[i]);
128     if(options.mode==bozo || options.mode==bez)
129     {
130       while(head3[i].size>0)
131 	delete1(&head3[i]);
132       while(head4[i].size>0)
133 	delete1(&head4[i]);
134     }
135   }
136 
137   free(head1);
138   free(head2);
139   if(options.mode==bozo || options.mode==bez)
140   {
141     free(head3);
142     free(head4);
143   }
144   inited=0;
145 }
146 
147 void
exit_bozo(int winno)148 exit_bozo(int winno)
149 {
150   exit_frame(winno);
151 }
152 
153 void
exit_circ(int winno)154 exit_circ(int winno)
155 {
156   exit_frame(winno);
157 }
158 
159 void
exit_qix(int winno)160 exit_qix(int winno)
161 {
162   exit_frame(winno);
163 }
164 
165 void
exit_qix4(int winno)166 exit_qix4(int winno)
167 {
168   exit_frame(winno);
169 }
170 
171 void
exit_bez(int winno)172 exit_bez(int winno)
173 {
174   exit_frame(winno);
175 }
176 
177 void
init_frame(int winno)178 init_frame(int winno)
179 {
180 /* make the first level */
181 
182 /*  fprintf(stderr,"Init'ing frame\n"); */
183 
184   /* 4 lists for each window, one for each point */
185 
186   if(!inited)
187   {
188 
189     head1=(ptList *)calloc(options.windows,sizeof(ptList));
190     head2=(ptList *)calloc(options.windows,sizeof(ptList));
191     if(options.mode==bozo || options.mode==bez)
192     {
193 	head3=(ptList *)calloc(options.windows,sizeof(ptList));
194 	head4=(ptList *)calloc(options.windows,sizeof(ptList));
195     }
196     inited=1;
197   }
198 
199 /* and now the second level */
200 
201 /* init the 4 points */
202   head1[winno].prev=NULL;
203   head1[winno].next=NULL;
204   head1[winno].size=0;
205   head2[winno].prev=NULL;
206   head2[winno].next=NULL;
207   head2[winno].size=0;
208   if(options.mode==bozo || options.mode==bez)
209   {
210     head3[winno].prev=NULL;
211     head3[winno].next=NULL;
212     head3[winno].size=0;
213     head4[winno].prev=NULL;
214     head4[winno].next=NULL;
215     head4[winno].size=0;
216   }
217   add(&head1[winno],1,winno);
218   add(&head2[winno],1,winno);
219   if(options.mode==bozo || options.mode==bez)
220   {
221     add(&head3[winno],1,winno);
222     add(&head4[winno],1,winno);
223   }
224 
225   if(options.multi)
226     HCV=1;
227   else
228     HCV=0;
229 }
230 
231 void
move_frame(int winno)232 move_frame(int winno)
233 {
234   if(head1[winno].size>=options.number)
235     delete1(&head1[winno]);
236   if(head2[winno].size>=options.number)
237     delete1(&head2[winno]);
238   if(options.mode==bozo || options.mode==bez)
239   {
240     if(head3[winno].size>=options.number)
241       delete1(&head3[winno]);
242     if(head4[winno].size>=options.number)
243       delete1(&head4[winno]);
244   }
245 }
246 
247 void
bounce(int winno)248 bounce(int winno)
249 {
250   /*#*#* Bouncing Code *#*#*/
251   add(&head1[winno],0,winno);
252   add(&head2[winno],0,winno);
253   if(options.mode==bozo|| options.mode==bez)
254   {
255     add(&head3[winno],0,winno);
256     add(&head4[winno],0,winno);
257   }
258 }
259 
260 void
draw_qix(int winno)261 draw_qix(int winno)
262 {
263   XPoint *ptr1,*ptr2,*ptr3,*ptr4;
264   int i;
265 
266   ptr1 = mirror(winno, head1[winno].next->x, head1[winno].next->y,
267 		options.mirrors+1, options.opt1);
268   ptr2 = mirror(winno, head2[winno].next->x, head2[winno].next->y,
269 		options.mirrors+1, options.opt1);
270   ptr3 = mirror(winno, head1[winno].prev->x, head1[winno].prev->y,
271 		options.mirrors+1, options.opt1);
272   ptr4 = mirror(winno, head2[winno].prev->x, head2[winno].prev->y,
273 	 	options.mirrors+1, options.opt1);
274 
275   for (i=0;i<=options.mirrors;i++)
276   {
277     XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
278 	      ptr1[i].x, ptr1[i].y, ptr2[i].x,ptr2[i].y);
279 
280     XDrawLine(display,window[winno],color_gcs[options.mono],
281 	      ptr3[i].x, ptr3[i].y, ptr4[i].x,ptr4[i].y);
282 
283   }
284 
285   free(ptr1);
286   free(ptr2);
287   free(ptr3);
288   free(ptr4);
289 }
290 
291 void
draw_qix4(int winno)292 draw_qix4(int winno)
293 {
294 
295   XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
296 	    head1[winno].next->x,head1[winno].next->y,
297 	    head2[winno].next->x,head2[winno].next->y);
298   XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
299 	    CX[winno]-head1[winno].next->x,head1[winno].next->y,
300 	    CX[winno]-head2[winno].next->x,head2[winno].next->y);
301   XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
302 	    head1[winno].next->x,CY[winno]-head1[winno].next->y,
303 	    head2[winno].next->x,CY[winno]-head2[winno].next->y);
304   XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
305 	    CX[winno]-head1[winno].next->x,CY[winno]-head1[winno].next->y,
306 	    CX[winno]-head2[winno].next->x,CY[winno]-head2[winno].next->y);
307 
308   XDrawLine(display,window[winno],color_gcs[options.mono],
309 	    head1[winno].prev->x,head1[winno].prev->y,
310 	    head2[winno].prev->x,head2[winno].prev->y);
311   XDrawLine(display,window[winno],color_gcs[options.mono],
312 	    CX[winno]-head1[winno].prev->x,head1[winno].prev->y,
313 	    CX[winno]-head2[winno].prev->x,head2[winno].prev->y);
314   XDrawLine(display,window[winno],color_gcs[options.mono],
315 	    head1[winno].prev->x,CY[winno]-head1[winno].prev->y,
316 	    head2[winno].prev->x,CY[winno]-head2[winno].prev->y);
317   XDrawLine(display,window[winno],color_gcs[options.mono],
318 	    CX[winno]-head1[winno].prev->x,CY[winno]-head1[winno].prev->y,
319 	    CX[winno]-head2[winno].prev->x,CY[winno]-head2[winno].prev->y);
320 }
321 
322 void
draw_bozo(int winno)323 draw_bozo(int winno)
324 {
325   /* draw the bozogon (actually just a quadrilateral,
326   ** but that's not as fun a name as 'bozogon' )
327   */
328   XPoint *ptr1,*ptr2,*ptr3,*ptr4,*ptr5,*ptr6,*ptr7,*ptr8;
329   int i;
330 
331   ptr1 = mirror(winno, head1[winno].next->x, head1[winno].next->y,
332 		options.mirrors+1, options.opt1);
333   ptr2 = mirror(winno, head2[winno].next->x, head2[winno].next->y,
334 		options.mirrors+1, options.opt1);
335   ptr3 = mirror(winno, head1[winno].prev->x, head1[winno].prev->y,
336 		options.mirrors+1, options.opt1);
337   ptr4 = mirror(winno, head2[winno].prev->x, head2[winno].prev->y,
338 	 	options.mirrors+1, options.opt1);
339   ptr5 = mirror(winno, head3[winno].next->x, head3[winno].next->y,
340 		options.mirrors+1, options.opt1);
341   ptr6 = mirror(winno, head4[winno].next->x, head4[winno].next->y,
342 		options.mirrors+1, options.opt1);
343   ptr7 = mirror(winno, head3[winno].prev->x, head3[winno].prev->y,
344 		options.mirrors+1, options.opt1);
345   ptr8 = mirror(winno, head4[winno].prev->x, head4[winno].prev->y,
346 	 	options.mirrors+1, options.opt1);
347 
348   for(i=0; i<=options.mirrors; i++)
349   {
350     XDrawLines(display,window[winno],color_gcs[head1[winno].next->pixel],
351 	     make_bozo(ptr1[i].x,ptr1[i].y,
352 		       ptr2[i].x,ptr2[i].y,
353 		       ptr5[i].x,ptr5[i].y,
354 		       ptr6[i].x,ptr6[i].y),
355 	     5,CoordModeOrigin);
356   /* and erase the last one */
357     XDrawLines(display,window[winno],color_gcs[options.mono],
358 	     make_bozo(ptr3[i].x,ptr3[i].y,
359 		       ptr4[i].x,ptr4[i].y,
360 		       ptr7[i].x,ptr7[i].y,
361 		       ptr8[i].x,ptr8[i].y),
362 	     5,CoordModeOrigin);
363   }
364   free(ptr1);
365   free(ptr2);
366   free(ptr3);
367   free(ptr4);
368   free(ptr5);
369   free(ptr6);
370   free(ptr7);
371   free(ptr8);
372 }
373 
374 void
draw_bez(int winno)375 draw_bez(int winno)
376 {
377   /* draw a Bezier curve (4 control points, 21 points on the curve */
378   int m,i,clr;
379   XPoint *ptr1,*ptr2,*ptr3,*ptr4,*ptr5,*ptr6,*ptr7,*ptr8;
380 
381   ptr1 = mirror(winno, head1[winno].next->x, head1[winno].next->y,
382 		options.mirrors+1, options.opt1);
383   ptr2 = mirror(winno, head2[winno].next->x, head2[winno].next->y,
384 		options.mirrors+1, options.opt1);
385   ptr3 = mirror(winno, head1[winno].prev->x, head1[winno].prev->y,
386 		options.mirrors+1, options.opt1);
387   ptr4 = mirror(winno, head2[winno].prev->x, head2[winno].prev->y,
388 	 	options.mirrors+1, options.opt1);
389   ptr5 = mirror(winno, head3[winno].next->x, head3[winno].next->y,
390 		options.mirrors+1, options.opt1);
391   ptr6 = mirror(winno, head4[winno].next->x, head4[winno].next->y,
392 		options.mirrors+1, options.opt1);
393   ptr7 = mirror(winno, head3[winno].prev->x, head3[winno].prev->y,
394 		options.mirrors+1, options.opt1);
395   ptr8 = mirror(winno, head4[winno].prev->x, head4[winno].prev->y,
396 	 	options.mirrors+1, options.opt1);
397 
398   for (m=0; m<=options.mirrors;m++)
399   {
400     XPoint* bezi;
401     bezi = Bezier(make_bozo(ptr1[m].x,ptr1[m].y,
402 			    ptr2[m].x,ptr2[m].y,
403 			    ptr5[m].x,ptr5[m].y,
404 			    ptr6[m].x,ptr6[m].y),21);
405 
406     clr=head1[winno].next->pixel;
407 
408     for(i=0;i<20;i++)
409     {
410       if(options.opt1 == 1)
411 	XDrawPoint(display, window[winno], color_gcs[clr],
412 		   bezi[i].x,bezi[i].y);
413       else
414 	XDrawLine(display, window[winno], color_gcs[clr],
415 		  bezi[i].x, bezi[i].y, bezi[i+1].x, bezi[i+1].y);
416       if(options.multi)
417 	clr = (clr+1)%numcolors;
418     }
419 
420     /* and erase the last one */
421     bezi =  Bezier(make_bozo(ptr3[m].x,ptr3[m].y,
422 			     ptr4[m].x,ptr4[m].y,
423 			     ptr7[m].x,ptr7[m].y,
424 			     ptr8[m].x,ptr8[m].y),21);
425 
426     if(options.opt1 == 1)
427       XDrawPoints(display,window[winno],color_gcs[options.mono],bezi,21,
428 		  CoordModeOrigin);
429     else
430       XDrawLines(display,window[winno],color_gcs[options.mono],bezi,21,
431 		 CoordModeOrigin);
432 
433   }
434   free(ptr1);
435   free(ptr2);
436   free(ptr3);
437   free(ptr4);
438   free(ptr5);
439   free(ptr6);
440   free(ptr7);
441   free(ptr8);
442 }
443 
444 
445 void
draw_circ(int winno)446 draw_circ(int winno)
447 {
448   XPoint *ptr1,*ptr2,*ptr3,*ptr4;
449   int i;
450 
451   ptr1 = mirror(winno, head1[winno].next->x, head1[winno].next->y,
452 		options.mirrors+1, options.opt1);
453   ptr2 = mirror(winno, head2[winno].next->x, head2[winno].next->y,
454 		options.mirrors+1, options.opt1);
455   ptr3 = mirror(winno, head1[winno].prev->x, head1[winno].prev->y,
456 		options.mirrors+1, options.opt1);
457   ptr4 = mirror(winno, head2[winno].prev->x, head2[winno].prev->y,
458 	 	options.mirrors+1, options.opt1);
459 
460   for(i=0;i<= options.mirrors; i++)
461   {
462     XDrawArc(display,window[winno],color_gcs[head1[winno].next->pixel],
463 	     ptr1[i].x,ptr1[i].y,
464 	     abs(ptr2[i].x-ptr1[i].x),
465 	     abs(ptr2[i].y-ptr1[i].y),
466 	     0, 64*360);
467 
468 
469     /* and erase the last one */
470     XDrawArc(display,window[winno],color_gcs[options.mono],
471 	     ptr3[i].x,ptr3[i].y,
472 	     abs(ptr4[i].x-ptr3[i].x),
473 	     abs(ptr4[i].y-ptr3[i].y),
474 	     0, 64*360);
475   }
476 
477   free(ptr1);
478   free(ptr2);
479   free(ptr3);
480   free(ptr4);
481 }
482 
483 void
draw_boxes(int winno)484 draw_boxes(int winno)
485 {
486   XPoint *ptr1,*ptr2,*ptr3,*ptr4;
487   int i;
488 
489   ptr1 = mirror(winno, head1[winno].next->x, head1[winno].next->y,
490 		options.mirrors+1, options.opt1);
491   ptr2 = mirror(winno, head2[winno].next->x, head2[winno].next->y,
492 		options.mirrors+1, options.opt1);
493   ptr3 = mirror(winno, head1[winno].prev->x, head1[winno].prev->y,
494 		options.mirrors+1, options.opt1);
495   ptr4 = mirror(winno, head2[winno].prev->x, head2[winno].prev->y,
496 	 	options.mirrors+1, options.opt1);
497 
498   /* draw the rectangles */
499 /*
500    I USED to be able to just call 'XDrawRectangle', but apparently X11R5's
501    version of that function doesn't deal with negative widths and heights.
502    So I'm using XDrawLines and an extra XDrawLine *sigh*. If your
503    XDrawRectangle works, uncomment them and use 'em
504 */
505   for(i=0; i<= options.mirrors; i++)
506   {
507 /*
508  XDrawRectangle(display,window[winno],color_gcs[head1[winno].next->pixel],
509  head1[winno].next->x,head1[winno].next->y,
510  head2[winno].next->x-head1[winno].next->x,
511  head2[winno].next->y-head1[winno].next->y );
512 */
513     XDrawLines(display,window[winno],color_gcs[head1[winno].next->pixel],
514 	       wrecked(ptr1[i].x, ptr1[i].y, ptr2[i].x, ptr2[i].y),
515 	       4,CoordModeOrigin);
516     XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
517 	      ptr1[i].x, ptr1[i].y, ptr1[i].x, ptr2[i].y);
518 
519     /* and erase the last one */
520 /*
521   XDrawRectangle(display,window[winno],color_gcs[options.mono],
522   head1[winno].prev->x,head1[winno].prev->y,
523   head2[winno].prev->x-head1[winno].prev->x,
524   head2[winno].prev->y-head1[winno].prev->y );
525 */
526     XDrawLines(display,window[winno],color_gcs[options.mono],
527 	       wrecked(ptr3[i].x, ptr3[i].y, ptr4[i].x, ptr4[i].y),
528 	       4,CoordModeOrigin);
529     XDrawLine(display,window[winno],color_gcs[options.mono],
530 	      ptr3[i].x,ptr3[i].y,
531 	      ptr3[i].x,ptr4[i].y);
532   }
533   free(ptr1);
534   free(ptr2);
535   free(ptr3);
536   free(ptr4);
537 }
538 
539 XPoint *
make_bozo(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4)540 make_bozo(int x1,int y1, int x2, int y2,
541 	  int x3,int y3, int x4, int y4)
542 {
543   static XPoint temp[5];
544 
545   temp[0].x = x1; temp[0].y = y1;
546   temp[1].x = x2; temp[1].y = y2;
547   temp[2].x = x3; temp[2].y = y3;
548   temp[3].x = x4; temp[3].y = y4;
549   temp[4].x = x1; temp[4].y = y1;
550 
551   return temp;
552 }
553