#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define FPS 50 extern const char *__progname; #define NPOINTS 1000 static const char *fbpath = "/dev/cgsix0"; typedef struct fxy FXY; typedef struct fig FIG; typedef struct ft FT; struct fxy { float x; float y; } ; struct fig { FIG *link; const char *name; int closed; double v[NPOINTS]; } ; struct ft { FIG *fig; int rot; unsigned int flags; #define FTF_NEG 0x00000001 #define FTF_REV 0x00000002 } ; static float curcol_r; static float curcol_g; static float curcol_b; static int curcol_plane; static float curcol_da; static float curcol_dx; static float curcol_dy; static float *curcol_xp; static float *curcol_yp; static float *curcol_zp; static void *fbmap; static int fbmaplen; static volatile struct cg6fbc *fbc; static volatile struct cg6thc *thc; static volatile struct brooktree *bt; static volatile unsigned char *vram; static int drawbit; static int timerfd; static volatile sig_atomic_t gotinfo; static FIG *figs; static FT prevftx; static FT prevfty; static double fraction; static FT nextftx; static FT nextfty; #define CMAP_BASE 20 /* must be a multiple of 4 */ #define COL_BG (CMAP_BASE) #define COL_FG (CMAP_BASE+3) #define PM_0 1 #define PM_1 2 __inline__ static float fclamp(float, float, float) __attribute__((__const__)); __inline__ static float fclamp(float v, float min, float max) { return((vmax)?max:v); } static void setcmap(int bit) { int i; int x; bt->addr = 0; for (i=0;icmap = 0; bt->cmap = 0; bt->cmap = 0; } for (i=0;i<4;i++) { x = i & (bit ? PM_1 : PM_0); bt->cmap = x ? 0xff000000&(unsigned int)(fclamp(curcol_r,0,1)*0xffffffff) : 0; bt->cmap = x ? 0xff000000&(unsigned int)(fclamp(curcol_g,0,1)*0xffffffff) : 0; bt->cmap = x ? 0xff000000&(unsigned int)(fclamp(curcol_b,0,1)*0xffffffff) : 0; } } static void draw(void) { while ((fbc->draw & 0xa0000000) == 0xa0000000) ; } static void drain(void) { while (fbc->s & 0x10000000) ; } static void add_fig(void (*fn)(FIG *)) { FIG *f; f = malloc(sizeof(FIG)); (*fn)(f); f->link = figs; figs = f; } static void line(FIG *f) { int i; f->closed = 0; f->name = "line"; for (i=0;iv[i] = i / (double)(NPOINTS-1); } #define TRIG(fn,n)\ static void fn##_##n(FIG *f) { int i; f->closed = 1; f->name = \ __FUNCTION__; for (i=0;iv[i] = \ (fn(i*n*2*M_PI/(NPOINTS-1)) + 1) / 2; } TRIG(sin,1) TRIG(sin,2) TRIG(sin,3) TRIG(sin,4) TRIG(sin,5) #undef TRIG #define TRIGGROW(fn,n,c)\ static void fn##_grow_##n(FIG *f) { int i; f->closed = c; f->name = \ __FUNCTION__; for (i=0;iv[i] = \ ((fn(i*n*2*M_PI/(NPOINTS-1)) * (1-(i/(NPOINTS*1.1)))) + 1) / 2; } TRIGGROW(sin,3,1) TRIGGROW(sin,5,1) TRIGGROW(sin,7,1) TRIGGROW(cos,3,0) TRIGGROW(cos,5,0) TRIGGROW(cos,7,0) #undef TRIGGROW static void modulated(FIG *f) { int i; double d; f->closed = 0; f->name = "modulated"; for (i=0;iv[i] = ((sin(d*M_PI) * sin(d*15*M_PI)) + 1) / 2; } } static __inline__ int gcd(int, int) __attribute__((__const__)); static __inline__ int gcd(int a, int b) { while (b) { int t; t = a % b; a = b; b = t; } return(a); } static void spirograph(FIG *f, int rteeth, int wteeth, double wfrac, int wanty) { int i; double r; double wca; double wa; i = gcd(rteeth,wteeth); rteeth /= i; wteeth /= i; r = 1 - (wteeth * (1-wfrac) / rteeth); f->closed = 1; for (i=0;iv[i] = wanty ? ( ( ( ((rteeth-wteeth) * sin(wca) / rteeth) + (wteeth * sin(wa) * wfrac / rteeth) ) / r ) + 1 ) / 2 : ( ( ( ((rteeth-wteeth) * cos(wca) / rteeth) + (wteeth * cos(wa) * wfrac / rteeth) ) / r ) + 1 ) / 2; } } #define SPIRO_x 0 #define SPIRO_y 1 #define SPIRO(n,r,w,p,c)\ static void spiro_##n##_##c(FIG *f) { f->name = __FUNCTION__; \ spirograph(f,r,w,p,SPIRO_##c); } SPIRO(a,5,3,.8,x) SPIRO(a,5,3,.8,y) SPIRO(b,5,3,.8,x) SPIRO(b,5,3,.8,y) SPIRO(c,7,3,.9,x) SPIRO(c,7,3,.9,y) SPIRO(d,11,4,.9,x) SPIRO(d,11,4,.9,y) SPIRO(e,11,8,.9,x) SPIRO(e,11,8,.9,y) SPIRO(f,15,8,1,x) SPIRO(f,15,8,1,y) #undef SPIRO_x #undef SPIRO_y #undef SPIRO static FT pickft(FIG *exc1, FIG *exc2, FIG *exc3) { int n; FIG *f; FIG *p; p = 0; n = 0; for (f=figs;f;f=f->link) { if ((f == exc1) || (f == exc2) || (f == exc3)) continue; n ++; if (random() % n) continue; p = f; } return((FT){ fig: p, rot: p->closed ? random()%(NPOINTS-1) : 0, flags: random() & (FTF_NEG|FTF_REV) }); } static void set_curcol_xyz(void) { switch (curcol_plane) { case 0: curcol_xp = &curcol_r; curcol_yp = &curcol_g; curcol_zp = &curcol_b; break; case 1: curcol_xp = &curcol_g; curcol_yp = &curcol_b; curcol_zp = &curcol_r; break; case 2: curcol_xp = &curcol_b; curcol_yp = &curcol_r; curcol_zp = &curcol_g; break; default: abort(); break; } } static void set_curcol_dxy(void) { while (curcol_da < -M_PI) curcol_da += 2*M_PI; while (curcol_da > M_PI) curcol_da -= 2*M_PI; curcol_dx = cos(curcol_da) / (10 * FPS); curcol_dy = sin(curcol_da) / (10 * FPS); } static void init(void) { int i; figs = 0; add_fig(&sin_1); add_fig(&sin_2); add_fig(&sin_3); add_fig(&sin_4); add_fig(&sin_5); add_fig(&sin_grow_3); add_fig(&sin_grow_5); add_fig(&sin_grow_7); add_fig(&cos_grow_3); add_fig(&cos_grow_5); add_fig(&cos_grow_7); add_fig(&modulated); add_fig(&spiro_a_x); add_fig(&spiro_a_y); add_fig(&spiro_b_x); add_fig(&spiro_b_y); add_fig(&spiro_c_x); add_fig(&spiro_c_y); add_fig(&spiro_d_x); add_fig(&spiro_d_y); add_fig(&spiro_e_x); add_fig(&spiro_e_y); add_fig(&spiro_f_x); add_fig(&spiro_f_y); add_fig(&line); srandom(time(0)); for (i=getpid();i>0;i--) random(); prevftx.fig = figs; prevftx.rot = 0; prevftx.flags = 0; prevfty = prevftx; nextftx = pickft(prevftx.fig,0,0); nextfty = pickft(prevftx.fig,nextftx.fig,0); fraction = 1; curcol_r = 1; curcol_g = 1; curcol_b = 1; curcol_plane = random() % 3; curcol_da = ((random() & 0x7fffffff) * (M_PI/2) / (double)0x80000000U) - M_PI; set_curcol_dxy(); set_curcol_xyz(); } static void fbsetup(void) { int fd; struct fbgattr a; fd = open(fbpath,O_RDWR,0); if (fd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } if ( (ioctl(fd,FBIOGATTR,&a) < 0) || (a.fbtype.fb_type != FBTYPE_SUNFAST_COLOR) || (a.fbtype.fb_width != 1152) || (a.fbtype.fb_height != 900) || (a.fbtype.fb_depth != 8) ) { fprintf(stderr,"%s: %s: not a usable cgsix\n",__progname,fbpath); exit(1); } fbmaplen = 0x16000 + a.fbtype.fb_size; fbmap = mmap(0,fbmaplen,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0x70000000); if (fbmap == MAP_FAILED) { fprintf(stderr,"%s: can't mmap %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } fbc = fbmap; thc = (void *)(0x5000+(unsigned char *)fbmap); bt = (void *)(0x2000+(unsigned char *)fbmap); vram = 0x16000 + (unsigned char *)fbmap; setcmap(1); drawbit = 0; fbc->bg = 0; fbc->pixelm = ~0; fbc->s = 0; fbc->mode = 0x00229540; /* not all bits known */ fbc->alu = 0xc0000000 /* GX_PLANE_MASK */ | 0x20000000 /* GX_PIXEL_ONES */ | 0x00800000 /* GX_ATTR_SUPP (?) */ | 0x00000000 /* GX_RAST_BOOL (?) */ | 0x00000000 /* GX_PLOT_PLOT (?) */ | 0x08000000 /* GX_PATTERN_ONES */ | 0x01000000 /* GX_POLYG_OVERLAP */ | ALU_FG; fbc->clip = 0; fbc->offx = 0; fbc->offy = 0; fbc->clipminx = 0; fbc->clipminy = 0; fbc->clipmaxx = 1151; fbc->clipmaxy = 899; fbc->fg = CMAP_BASE; fbc->pm = ~0; drain(); fbc->arecty = 0; fbc->arectx = 0; fbc->arecty = 900; fbc->arectx = 1152; draw(); drain(); close(fd); } static void timersetup(void) { struct itimerval itv; timerfd = socket(AF_TIMER,SOCK_STREAM,0); if (timerfd < 0) { fprintf(stderr,"%s: AF_TIMER socket: %s\n",__progname,strerror(errno)); exit(1); } itv.it_interval.tv_sec = 0; itv.it_interval.tv_usec = 1000000 / FPS; itv.it_value = itv.it_interval; write(timerfd,&itv,sizeof(itv)); } static double getcoord(const FT *ft, int inx) { if (ft->fig->closed) inx = (inx + ft->rot) % (NPOINTS-1); if (ft->flags & FTF_REV) inx = NPOINTS - (ft->fig->closed ? 2 : 1) - inx; return((ft->flags&FTF_NEG)?1-ft->fig->v[inx]:ft->fig->v[inx]); } static FXY interp(FXY, float, FXY) __attribute__((__const__)); static FXY interp(FXY a, float f, FXY b) { return((FXY){x:(a.x*(1-f))+(b.x*f),y:(a.y*(1-f))+(b.y*f)}); } static void drawit(void) { int i; FXY prev; FXY next; FXY cur; float f; f = (cos(fraction*M_PI) + 1) / 2; for (i=0;ialiney = (int)(cur.y*899); fbc->alinex = (int)(cur.x*1151); if (i) draw(); } drain(); } static void step(void) { float cx; float cy; int set; fbc->pixelm = ~0; fbc->s = 0; fbc->mode = 0x00229540; /* not all bits known */ fbc->alu = 0xc0000000 /* GX_PLANE_MASK */ | 0x20000000 /* GX_PIXEL_ONES */ | 0x00800000 /* GX_ATTR_SUPP (?) */ | 0x00000000 /* GX_RAST_BOOL (?) */ | 0x00000000 /* GX_PLOT_PLOT (?) */ | 0x08000000 /* GX_PATTERN_ONES */ | 0x01000000 /* GX_POLYG_OVERLAP */ | ALU_FG; fbc->clip = 0; fbc->offx = 0; fbc->offy = 0; fbc->clipminx = 0; fbc->clipminy = 0; fbc->clipmaxx = 1151; fbc->clipmaxy = 899; fbc->pm = drawbit ? ~PM_0 : ~PM_1; fbc->fg = CMAP_BASE; fbc->arecty = 0; fbc->arectx = 0; fbc->arecty = 899; fbc->arectx = 1151; draw(); fbc->fg = 3; fbc->pm = drawbit ? PM_1 : PM_0; drawit(); setcmap(drawbit); drawbit = ! drawbit; if (fraction == 1) { prevftx = nextftx; prevfty = nextfty; if (prevftx.fig->closed && prevfty.fig->closed) { int r; r = random() % (NPOINTS-1); prevftx.rot = (prevftx.rot + r) % (NPOINTS-1); prevfty.rot = (prevfty.rot + r) % (NPOINTS-1); } nextftx = pickft(prevftx.fig,prevfty.fig,0); nextfty = pickft(prevftx.fig,prevfty.fig,nextftx.fig); fraction = 0; } else { fraction += 1 / (double)(5 * FPS); if (fraction > 1) fraction = 1; } set = 0; cx = *curcol_xp += curcol_dx; cy = *curcol_yp += curcol_dy; if (cx < 0) { *curcol_xp = 0; curcol_da = M_PI - curcol_da; set = 1; } else if (cy < 0) { *curcol_yp = 0; curcol_da = - curcol_da; set = 1; } else if (cx > 1) { *curcol_xp = 1; curcol_plane = (curcol_plane+1) % 3; curcol_da -= M_PI / 2; set = 1; } else if (cy > 1) { *curcol_yp = 1; curcol_plane = (curcol_plane+2) % 3; curcol_da += M_PI / 2; set = 1; } if (set) { set_curcol_xyz(); curcol_da += ((random() & 0x7fffffff) / (double)0x80000000U) * .1; set_curcol_dxy(); } } static void siginfo_handler(int sig __attribute__((__unused__))) { gotinfo = 1; } static void sigsetup(void) { struct sigaction sa; sa.sa_handler = siginfo_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGINFO,&sa,0); gotinfo = 0; } static void print_ft(const FT *ft) { if (ft->flags & FTF_NEG) printf("-"); if (ft->flags & FTF_REV) printf("~"); printf("%s",ft->fig->name); if (ft->fig->closed) printf("(%d)",ft->rot); } static void printinfo(void) { printf("["); print_ft(&prevftx); printf(","); print_ft(&prevfty); printf("] %g [",fraction); print_ft(&nextftx); printf(","); print_ft(&nextfty); printf("]\n"); fflush(0); } int main(void); int main(void) { init(); fbsetup(); sigsetup(); timersetup(); while (1) { struct timersock_event e; read(timerfd,&e,sizeof(e)); if (gotinfo) { gotinfo = 0; printinfo(); } step(); } }