static void do_twinkle(Display *dpy, Window window) { Colormap cmap; XWindowAttributes xgwa; int got_color = 0; XColor color[maxps]; XColor bgcolor; int p,f,nt, sx,sy, resets,lastresets,cnt; XClearWindow (dpy, window); XGetWindowAttributes (dpy, window, &xgwa); cmap = xgwa.colormap; scrwid = xgwa.width; scrhei = xgwa.height; /* Setup colours */ hsv_to_rgb (0.0, 0.0, 0.0, &bgcolor.red, &bgcolor.green, &bgcolor.blue); got_color = XAllocColor (dpy, cmap, &bgcolor); for (p=0;p<ps;p++) { if (!mono_p) hsv_to_rgb (random()%360, .6+.4*myrnd(), .6+.4*myrnd(), &color[p].red, &color[p].green, &color[p].blue); /* hsv_to_rgb (random()%360, 1.0, 1.0, &color[p].red, &color[p].green, &color[p].blue); for stronger colours! */ if ((!mono_p) && (got_color = XAllocColor (dpy, cmap, &color[p]))) { } else { if (p>0) color[p]=color[0]; else color[p].pixel=default_fg_pixel; } } /* Set up parameter movements for the different forcefields */ name[1] = "Velocity"; op[1] = 1; damp[1] = .999; force[1] = .002; name[2] = "Rotation"; op[2] = 0; damp[2] = .999; force[2] = .002; name[3] = "Drip"; op[3] = 1; damp[3] = .999; force[3] = .005; name[4] = "Dribble"; op[4] = 1; damp[4] = .999; force[4] = .005; name[5] = "Slide"; op[5] = 0; damp[5] = .999; force[5] = .002; name[6] = "Accelerate"; op[6] = 1.0; damp[6] = .999; force[6] = .005; name[7] = "xDisplace"; op[7] = 0; damp[7] = .999; force[7] = .005; name[8] = "yDisplace"; op[8] = 0; damp[8] = .999; force[8] = .005; /* 0 and 9 are options for splitting displacements [no var] */ name[0] = "Split"; op[0] = 0; damp[0] = 0; force[0] = 0; name[9] = "2d/3d split"; op[9] = 0; damp[9] = 0; force[9] = 0; /* Initialise parameters to optimum, all off */ for (f=0;f<fs;f++) { var[f]=op[f]; fon[f]=0; } /* Initialise stars */ for (p=0;p<ps;p++) stars_newp(p); /* tx[nt],ty[nt] remeber earlier screen plots (tails of stars) which are deleted when nt comes round again */ nt=0; resets=0; while (1) { /* Move current points */ lastresets=resets; resets=0; for (p=0;p<ps;p++) { /* Erase old */ XSetForeground (dpy, draw_gc, bgcolor.pixel); XDrawPoint(dpy,window,draw_gc,tx[nt],ty[nt]); /* Move */ stars_move(p); /* If moved off screen, create a new one */ if (cx[p]<-1.0 || cx[p]>+1.0 || cy[p]<-1.0 || cy[p]>+1.0 || fabs(cx[p])<.001 || fabs(cy[p])<.001) { stars_newp(p); resets++; } else if (myrnd()>0.99) /* Reset at random */ stars_newp(p); /* Draw point */ sx=stars_scrpos_x(p); sy=stars_scrpos_y(p); XSetForeground (dpy, draw_gc, color[p].pixel); XDrawPoint(dpy,window,draw_gc,sx,sy); /* Remember it for removal later */ tx[nt]=sx; ty[nt]=sy; nt=(nt+1)%(ps*ts); } /* Adjust force fields */ cnt=0; for (f=0;f<fs;f++) { if (meters) { /* Remove meter from display */ XSetForeground(dpy, draw_gc, bgcolor.pixel); stars_draw_meter(dpy,window,draw_gc,f); } /* Adjust forcefield's parameter */ var[f]=stars_perturb(var[f],op[f],damp[f],force[f]); if (myrnd()>0.998) /* Turn it on/off ? */ fon[f]=(myrnd()<0.0); /* fon[f]=!fon[f]; */ if (meters) { /* Redraw the meter */ XSetForeground(dpy, draw_gc, color[f].pixel); stars_draw_meter(dpy,window,draw_gc,f); } if (fon[f]) cnt++; } if (cnt==0) { /* Ensure at least one is on! */ f=random() % fs; fon[f]=1; } if (meters) { XSetForeground(dpy, draw_gc, bgcolor.pixel); XDrawRectangle(dpy,window,draw_gc,0,0,lastresets*5,3); XSetForeground(dpy, draw_gc, default_fg_pixel); XDrawRectangle(dpy,window,draw_gc,0,0,resets*5,3); } /* if (resets*5>scrwid) { Turn one off a field if too many points are flying off screen */ /* This was a problem when one of the force-fields was acting wrong, but not really needed any more unless we need to debug new ones ...! */ /* for (f=0;f<fs;f++) if (fon[f]) printf("%i",f); printf("\n"); XSync (dpy, False); screenhack_handle_events (dpy); sleep(1); do { // In fact this bit might go wrong if f=random() % fs; // we have not ensured at least one is on (above) } while (!fon[f]); fon[f]=0; } */ XSync (dpy, False); screenhack_handle_events (dpy); } }
static unsigned long whirlwindwarp_draw (Display *dpy, Window window, void *closure) { struct state *st = (struct state *) closure; /* time_t lastframe = time((time_t) 0); */ if (!st->initted) { st->initted = 1; XClearWindow (st->dpy, st->window); XGetWindowAttributes (st->dpy, st->window, &st->xgwa); st->scrwid = st->xgwa.width; st->scrhei = st->xgwa.height; st->starsize=st->scrhei/480; if (st->starsize<=0) st->starsize=1; /* Setup colours */ hsv_to_rgb (0.0, 0.0, 0.0, &st->bgcolor.red, &st->bgcolor.green, &st->bgcolor.blue); st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, &st->bgcolor); st->colsavailable=0; for (st->p=0;st->p<st->ps;st->p++) { if (!mono_p) hsv_to_rgb (random()%360, .6+.4*myrnd(), .6+.4*myrnd(), &st->color[st->p].red, &st->color[st->p].green, &st->color[st->p].blue); /* hsv_to_rgb (random()%360, 1.0, 1.0, &color[p].red, &color[p].green, &color[p].blue); for stronger colours! */ if ((!mono_p) && (st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, &st->color[st->p]))) { st->colsavailable=st->p; } else { if (st->colsavailable>0) /* assign colours from those already allocated */ st->color[st->p]=st->color[ st->p % st->colsavailable ]; else st->color[st->p].pixel=st->default_fg_pixel; } } /* Set up central (optimal) points for each different forcefield */ st->op[1] = 1; st->name[1] = "Warp"; st->op[2] = 0; st->name[2] = "Rotation"; st->op[3] = 1; st->name[3] = "Horizontal asymptote"; st->op[4] = 0; st->name[4] = "Vertical asymptote"; st->op[5] = 1; st->name[5] = "Vertical asymptote right"; st->op[6] = 1; st->name[6] = "Squirge x"; st->op[7] = 1; st->name[7] = "Squirge y"; st->op[0] = 0; st->name[0] = "Split number (inactive)"; st->op[8] = 0; st->name[8] = "Split velocity x"; st->op[9] = 0; st->name[9] = "Split velocity y"; st->op[10] = 0; st->name[10] = "Horizontal wave amplitude"; st->op[11] = myrnd()*3.141; st->name[11] = "Horizontal wave phase (inactive)"; st->op[12] = 0.01; st->name[12] = "Horizontal wave frequency (inactive)"; st->op[13] = 0; st->name[13] = "Vertical wave amplitude"; st->op[14] = myrnd()*3.141; st->name[14] = "Vertical wave phase (inactive)"; st->op[15] = 0.01; st->name[15] = "Vertical wave frequency (inactive)"; /* Initialise parameters to optimum, all off */ for (st->f=0;st->f<fs;st->f++) { st->var[st->f]=st->op[st->f]; st->fon[st->f]=( myrnd()>0.5 ? 1 : 0 ); st->acc[st->f]=0.02 * myrnd(); st->vel[st->f]=0; } /* Initialise stars */ for (st->p=0;st->p<st->ps;st->p++) stars_newp(st, st->p); /* tx[nt],ty[nt] remember earlier screen plots (tails of stars) which are deleted when nt comes round again */ st->nt = 0; st->resets = 0; st->hue = 180 + 180*myrnd(); gettimeofday(&st->lastframe, NULL); } if (myrnd()>0.75) { /* Change one of the allocated colours to something near the current hue. */ /* By changing a random colour, we sometimes get a tight colour spread, sometime a diverse one. */ int pp = st->colsavailable * (0.5+myrnd()/2); hsv_to_rgb (st->hue, .6+.4*myrnd(), .6+.4*myrnd(), &st->color[pp].red, &st->color[pp].green, &st->color[pp].blue); if ((!mono_p) && (st->got_color = XAllocColor (st->dpy, st->xgwa.colormap, &st->color[pp]))) { } st->hue = st->hue + 0.5 + myrnd()*9.0; if (st->hue<0) st->hue+=360; if (st->hue>=360) st->hue-=360; } /* Move current points */ st->lastresets=st->resets; st->resets=0; for (st->p=0;st->p<st->ps;st->p++) { /* Erase old */ XSetForeground (st->dpy, st->draw_gc, st->bgcolor.pixel); /* XDrawPoint(dpy,window,draw_gc,tx[nt],ty[nt]); */ XFillRectangle(st->dpy,st->window,st->draw_gc,st->tx[st->nt],st->ty[st->nt],st->starsize,st->starsize); /* Move */ stars_move(st, st->p); /* If moved off screen, create a new one */ if (st->cx[st->p]<=-0.9999 || st->cx[st->p]>=+0.9999 || st->cy[st->p]<=-0.9999 || st->cy[st->p]>=+0.9999 || fabs(st->cx[st->p])<.0001 || fabs(st->cy[st->p])<.0001) { stars_newp(st, st->p); st->resets++; } else if (myrnd()>0.99) /* Reset at random */ stars_newp(st, st->p); /* Draw point */ st->sx=stars_scrpos_x(st, st->p); st->sy=stars_scrpos_y(st, st->p); XSetForeground (st->dpy, st->draw_gc, st->color[st->p].pixel); /* XDrawPoint(dpy,window,draw_gc,sx,sy); */ XFillRectangle(st->dpy,st->window,st->draw_gc,st->sx,st->sy,st->starsize,st->starsize); /* Remember it for removal later */ st->tx[st->nt]=st->sx; st->ty[st->nt]=st->sy; st->nt=(st->nt+1)%(st->ps*st->ts); } /* Adjust force fields */ st->cnt=0; for (st->f=0;st->f<fs;st->f++) { if (st->meters) { /* Remove meter from display */ XSetForeground(st->dpy, st->draw_gc, st->bgcolor.pixel); stars_draw_meter(st,st->f); } /* Adjust forcefield's parameter */ if (st->fon[st->f]) { /* This configuration produces var[f]s usually below 0.01 */ st->acc[st->f]=stars_perturb(st->acc[st->f],0,0.98,0.005); st->vel[st->f]=stars_perturb(st->vel[st->f]+0.03*st->acc[st->f],0,0.995,0.0); st->var[st->f]=st->op[st->f]+(st->var[st->f]-st->op[st->f])*0.9995+0.001*st->vel[st->f]; } /* fprintf(stderr,"f=%i fon=%i acc=%f vel=%f var=%f\n",f,fon[f],acc[f],vel[f],var[f]); */ /* Decide whether to turn this forcefield on or off. */ /* prob_on makes the "splitting" effects less likely than the rest */ #define prob_on ( st->f==8 || st->f==9 ? 0.999975 : 0.9999 ) if ( st->fon[st->f]==0 && myrnd()>prob_on ) { turn_on_field(st, st->f); } else if ( st->fon[st->f]!=0 && myrnd()>0.99 && fabs(st->var[st->f]-st->op[st->f])<0.0005 && fabs(st->vel[st->f])<0.005 /* && fabs(acc[f])<0.01 */ ) { /* We only turn it off if it has gently returned to its optimal (as opposed to rapidly passing through it). */ st->fon[st->f] = 0; } if (st->meters) { /* Redraw the meter */ XSetForeground(st->dpy, st->draw_gc, st->color[st->f].pixel); stars_draw_meter(st,st->f); } if (st->fon[st->f]) st->cnt++; } /* Ensure at least three forcefields are on. * BUG: Picking randomly might not be enough since 0,11,12,14 and 15 do nothing! * But then what's wrong with a rare gentle twinkle?! */ if (st->cnt<3) { st->f=random() % fs; turn_on_field(st, st->f); } if (st->meters) { XSetForeground(st->dpy, st->draw_gc, st->bgcolor.pixel); XDrawRectangle(st->dpy,st->window,st->draw_gc,0,0,st->lastresets*5,3); XSetForeground(st->dpy, st->draw_gc, st->default_fg_pixel); XDrawRectangle(st->dpy,st->window,st->draw_gc,0,0,st->resets*5,3); } /* Cap frames per second; do not go above specified fps: */ { unsigned long this_delay = 0; int maxfps = 200; long utimeperframe = 1000000/maxfps; struct timeval now; long timediff; gettimeofday(&now, NULL); timediff = now.tv_sec*1000000 + now.tv_usec - st->lastframe.tv_sec*1000000 - st->lastframe.tv_usec; if (timediff < utimeperframe) { /* fprintf(stderr,"sleeping for %i\n",utimeperframe-timediff); */ this_delay = (utimeperframe-timediff); } st->lastframe = now; return this_delay; } }