/* * Copyright (c) 2004-2009 Steve Sundstrom * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ #include "screenhack.h" #include "colors.h" #include "hsv.h" #include #include #include /*#include */ #define MODE_CREATE 0 /* init, create, then finish sleep */ #define MODE_ERASE 1 /* erase, then reset colors */ #define MODE_DRAW 2 #define DIR_NONE 0 #define DIR_UP 1 #define DIR_DOWN 2 #define DIR_LEFT 3 #define DIR_RIGHT 4 #define LINE_FORCE 1 #define LINE_NEW 2 #define LINE_BRIN 3 #define LINE_BROUT 4 #define PT_UL 0 #define PT_MP 1 #define PT_LR 2 #define PT_NL 3 #define D3D_NONE 0 #define D3D_BLOCK 1 #define D3D_NEON 2 #define D3D_TILED 3 #define TILE_RANDOM 0 #define TILE_FLAT 1 #define TILE_THIN 2 #define TILE_OUTLINE 3 #define TILE_BLOCK 4 #define TILE_NEON 5 #define TILE_TILED 6 #define BASECOLORS 30 #define SHADES 12 #define MAXCOLORS 40 #define LAYERS 4 #define PATTERNS 40 #define SHAPES 18 #define DRAWORDERS 40 #define COLORMAPS 20 #define WAVES 6 #define STRETCHES 8 struct lineStruct { unsigned int x, y, len, obj, color, ndol; int deo; Bool hv; }; struct gridStruct { unsigned int line, hl, hr, vu, vd, dhl, dhr, dvu, dvd; }; /* basically the same as global variables, but used to keep them in a bucket and pass them around easier like the original C++ implementation */ struct state { /* window values */ Display *display; Window window; XWindowAttributes xgwa; GC fgc, bgc; XColor colors[255]; /* memory values */ struct lineStruct *dline, *eline; struct gridStruct *grid; unsigned int *zlist, *fdol; Bool *odi; /* draw, erase, fill, init, line, object, z indexes */ unsigned int di, ei, fi, ii, bi, li, eli, oi, zi; /* size variables */ int gridx, gridy; /* grid size */ unsigned int gridn; int lwid, bwid, swid;/* line width, background width, shadow width */ int narray, max_wxh; int elwid, elpu, egridx, egridy; /* for now */ /* fill variables */ int bnratio; /* ratio of branch lines to new lines */ int maxlen; /* maximum length of line */ int forcemax; /* make line be max possible length */ int olen; /* open length set by findopen */ int bln; /* blocking line number set by findopen, -1=edge */ /* color variables */ int ncolors; /* number of colors for screen */ int shades; int rco[MAXCOLORS]; /* random ordering of colors for deo */ int cmap; int layers; Bool newcols; /* can we create new colormaps with each screen */ /* draw variables */ int dmap, emap; /* pattern by which line draw order is determined */ int dvar, evar; /* random number added to .deo to vary */ int ddir, edir; /* draw/erase in forward direction or reverse */ int lpu; /* lines drawn per update used to adjust speed */ int d3d; int round; int outline; /* layered draw variables */ int pattern[LAYERS], shape[LAYERS], mix[LAYERS]; int csw[LAYERS], wsx[LAYERS], wsy[LAYERS], sec[LAYERS]; int cs1[LAYERS], cs2[LAYERS], cs3[LAYERS]; int cs4[LAYERS]; int wave[LAYERS], waveh[LAYERS], wavel[LAYERS]; int rx1[LAYERS], rx2[LAYERS], rx3[LAYERS]; int ry1[LAYERS], ry2[LAYERS], ry3[LAYERS]; /* misc variables */ int mode, sleep, speed, tile, dialog; Bool grid_full, resized; struct timeval time; }; static int _min(int a, int b) { if (a<=b) return(a); return(b); } static int _max(int a, int b) { if (a>=b) return(a); return(b); } static int _dist(struct state *st, int x1, int x2, int y1, int y2, int s) { double xd=x1-x2; double yd=y1-y2; switch(s) { case 0: return((int)sqrt(xd*xd+yd*yd)); case 1: return((int)sqrt(xd*xd*st->cs1[0]*2+yd*yd)); case 2: return((int)sqrt(xd*xd+yd*yd*st->cs2[0]*2)); default: return((int)sqrt(xd*xd*st->cs1[0]/st->cs2[0]+yd*yd*st->cs3[0]/st->cs4[0])); } } static int _wave(struct state *st, int x, int h, int l, int wave) { l+=1; switch(wave) { case 0: /* cos wave*/ return((int)(cos((double)x*M_PI/l)*h)); case 1: /* double wave*/ case 2: /* double wave*/ return((int)(cos((double)x*M_PI/l)*h)+(int)(sin((double)x*M_PI/l/st->cs1[1])*h)); case 3: /* zig zag */ return(abs((x%(l*2)-l))*h/l); case 4: /* giant zig zag */ return(abs((x%(l*4)-l*2))*h*3/l); case 5: /* sawtooth */ return((x%(l))*h/l); default: /* no wave */ return(0); } } static int _triangle(struct state *st, int x, int y, int rx, int ry, int t) { switch(t) { case 1: return(_min(_min(x+y+rx-(st->gridx/2),st->gridx-x+y),(st->gridy-y+(ry/2))*3/2)); case 2: return(_min(_min(x-rx,y-ry),(rx+ry-x-y)*2/3)); case 3: return(_min(_min(st->gridx-x-rx,y-ry),(rx+ry-st->gridx+x-y)*2/3)); case 4: return(_min(_min(x-rx,st->gridy-y-ry),(rx+ry-x-st->gridy+y)*2/3)); } return(_min(_min(st->gridx-x-rx,st->gridy-y-ry),(rx+ry-st->gridx+x-st->gridy+y)*2/3)); } static void _init_zlist(struct state *st) { unsigned int tmp, y, z; st->gridx=st->xgwa.width/st->lwid; st->gridy=st->xgwa.height/st->lwid; if ((st->gridx <= 0) || (st->gridy <= 0)) abort(); st->gridn=st->gridx*st->gridy; /* clear grid */ for (z=0; zgridn; z++) { st->grid[z].line=st->grid[z].hl=st->grid[z].hr=st->grid[z].vu=st->grid[z].vd=st->grid[z].dhl=st->grid[z].dhr=st->grid[z].dvu=st->grid[z].dvd=0; st->zlist[z]=z; } /* rather than pull x,y points randomly and wait to hit final empy cells a list of all points is created and mixed so empty cells do get hit last */ for (z=0; zgridn; z++) { y=random()%st->gridn; tmp=st->zlist[y]; st->zlist[y]=st->zlist[z]; st->zlist[z]=tmp; } } static void make_color_ramp_rgb (Screen *screen, Visual *visual, Colormap cmap, int r1, int g1, int b1, int r2, int g2, int b2, XColor *colors, int *ncolorsP, Bool closed_p) { int h1, h2; double s1, s2, v1, v2; rgb_to_hsv(r1, g1, b1, &h1, &s1, &v1); rgb_to_hsv(r2, g2, b2, &h2, &s2, &v2); make_color_ramp(screen, visual, cmap, h1, s1, v1, h2, s2, v2, colors, ncolorsP, False, True, 0); } static void _init_colors(struct state *st) { int col[BASECOLORS]; int c1, c2, c3, h1, h2, h3; int r1, g1, b1, r2, g2, b2, r3, g3, b3; double s1, s2, s3, v1, v2, v3; XColor tmp_col1[16], tmp_col2[16], tmp_col3[16]; unsigned short basecol[BASECOLORS][3]={ /* 0 dgray */ {0x3333,0x3333,0x3333}, /* 1 dbrown */ {0x6666,0x3333,0x0000}, /* 2 dred */ {0x9999,0x0000,0x0000}, /* 3 orange */ {0xFFFF,0x6666,0x0000}, /* 4 gold */ {0xFFFF,0xCCCC,0x0000}, /* 5 olive */ {0x6666,0x6666,0x0000}, /* 6 ivy */ {0x0000,0x6666,0x0000}, /* 7 dgreen */ {0x0000,0x9999,0x0000}, /* 8 bluegray */ {0x3333,0x6666,0x6666}, /* 9 dblue */ {0x0000,0x0000,0x9999}, /* 10 blue */ {0x3333,0x3333,0xFFFF}, /* 11 dpurple */ {0x6666,0x0000,0xCCCC}, /* 12 purple */ {0x6666,0x3333,0xFFFF}, /* 13 violet */ {0x9999,0x3333,0x9999}, /* 14 magenta */ {0xCCCC,0x3333,0xCCCC}, /* lights */ /* 15 gray */ {0x3333,0x3333,0x3333}, /* 16 brown */ {0x9999,0x6666,0x3333}, /* 17 tan */ {0xCCCC,0x9999,0x3333}, /* 18 red */ {0xFFFF,0x0000,0x0000}, /* 19 lorange */ {0xFFFF,0x9999,0x0000}, /* 20 yellow */ {0xFFFF,0xFFFF,0x0000}, /* 21 lolive */ {0x9999,0x9999,0x0000}, /* 22 green */ {0x3333,0xCCCC,0x0000}, /* 23 lgreen */ {0x3333,0xFFFF,0x3333}, /* 24 cyan */ {0x0000,0xCCCC,0xCCCC}, /* 25 sky */ {0x3333,0xFFFF,0xFFFF}, /* 26 marine */ {0x3333,0x6666,0xFFFF}, /* 27 lblue */ {0x3333,0xCCCC,0xFFFF}, /* 28 lpurple */ {0x9999,0x9999,0xFFFF}, /* 29 pink */ {0xFFFF,0x9999,0xFFFF}}; if (st->d3d) { st->shades = (st->d3d==D3D_TILED) ? 5 : st->lwid/2+1; st->ncolors=4+random()%4; if (st->cmap>0) { /* tint the basecolors a bit */ for (c1=0; c1cmap%4) { case 0: /* all */ for (c1=0; c1ncolors; c1++) col[c1]=random()%BASECOLORS; break; case 1: /* darks */ for (c1=0; c1ncolors; c1++) col[c1]=random()%15; break; case 2: /* semi consecutive darks */ col[0]=random()%15; for (c1=1; c1ncolors; c1++) col[c1]=(col[c1-1]+1+random()%2)%15; break; case 3: /* consecutive darks */ col[0]=random()%(15-st->ncolors); for (c1=1; c1ncolors; c1++) col[c1]=col[c1-1]+1; break; } for (c1=0; c1ncolors; c1++) { /* adjust colors already set */ for (h1=c1*st->shades-1; h1>=0; h1--) st->colors[h1+st->shades]=st->colors[h1]; make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, basecol[col[c1]][0], basecol[col[c1]][1], basecol[col[c1]][2], 0xFFFF, 0xFFFF, 0xFFFF, st->colors, &st->shades, False); } return; } /* not 3d */ st->shades=1; if (st->cmap%2) { /* basecolors */ if (random()%3) { c1=random()%15; c2=(c1+3+(random()%5))%15; c3=(c2+3+(random()%5))%15; } else { c1=random()%BASECOLORS; c2=(c1+5+(random()%10))%BASECOLORS; c3=(c2+5+(random()%10))%BASECOLORS; } r1=basecol[c1][0]; g1=basecol[c1][1]; b1=basecol[c1][2]; r2=basecol[c2][0]; g2=basecol[c2][1]; b2=basecol[c2][2]; r3=basecol[c3][0]; g3=basecol[c3][1]; b3=basecol[c3][2]; } else { /* random rgb's */ r1=random()%65535; g1=random()%65535; b1=random()%65535; r2=(r1+16384+random()%32768)%65535; g2=(g1+16384+random()%32768)%65535; b2=(b1+16384+random()%32768)%65535; r3=(r2+16384+random()%32768)%65535; g3=(g2+16384+random()%32768)%65535; b3=(b2+16384+random()%32768)%65535; } switch(st->cmap) { case 0: /* make_color_ramp color->color */ case 1: case 2: /* make_color_ramp color->white */ case 3: st->ncolors=5+random()%5; if (st->cmap>1) r2=g2=b2=0xFFFF; make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, r1, g1, b1, r2, g2, b2, st->colors, &st->ncolors, random()%2); break; case 4: /* 3 color make_color_loop */ case 5: case 6: case 7: st->ncolors=8+random()%12; rgb_to_hsv(r1, g1, b1, &h1, &s1, &v1); rgb_to_hsv(r2, g2, b2, &h2, &s2, &v2); rgb_to_hsv(r3, g3, b3, &h3, &s3, &v3); make_color_loop(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, h1, s1, v1, h2, s2, v2, h3, s3, v3, st->colors, &st->ncolors, True, False); break; case 8: /* random smooth */ case 9: st->ncolors=(random()%4)*6+12; make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, st->colors, &st->ncolors, True, False, True); break; case 10: /* rainbow */ st->ncolors=(random()%4)*6+12; make_uniform_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, st->colors, &st->ncolors, True, False, True); break; case 11: /* dark to light blend */ case 12: case 13: case 14: st->ncolors=7; make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, r1, g1, b1, 0xFFFF, 0xFFFF, 0xFFFF, tmp_col1, &st->ncolors, False); make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, r2, g2, b2, 0xFFFF, 0xFFFF, 0xFFFF, tmp_col2, &st->ncolors, False); if (st->cmap<13) { for(c1=0; c1<=4; c1++) { st->colors[c1*2]=tmp_col1[c1]; st->colors[c1*2+1]=tmp_col2[c1]; } st->ncolors=10; } else { make_color_ramp_rgb(st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, r3, g3, b3, 0xFFFF, 0xFFFF, 0xFFFF, tmp_col3, &st->ncolors, False); for(c1=0; c1<=4; c1++) { st->colors[c1*3]=tmp_col1[c1]; st->colors[c1*3+1]=tmp_col2[c1]; st->colors[c1*3+2]=tmp_col3[c1]; } st->ncolors=15; } break; default: /* random */ st->ncolors=(random()%4)*6+12; make_random_colormap (st->xgwa.screen, st->xgwa.visual, st->xgwa.colormap, st->colors, &st->ncolors, False, True, False, True); break; } /* set random color order for drawing and erasing */ for (c1=0; c1rco[c1]=c1; for (c1=0; c1rco[c1]; st->rco[c1]=st->rco[c3]; st->rco[c3]=c2; } } static int _comparedeo(const void *i, const void *j) { struct lineStruct *h1, *h2; h1=(struct lineStruct *)i; h2=(struct lineStruct *)j; if (h1->deo > h2->deo) return(1); if (h1->deo < h2->deo) return(-1); return(0); } static int _hv(struct state *st, int x, int y, int d1, int d2, int pn, Bool de) { int v1, v2, r; switch (d1) { case 0: v1 = (de) ? st->egridx-x : st->gridx-x; break; case 1: v1 = y; break; case 2: v1 = x; break; default: v1 = (de) ? st->egridy-y : st->gridy-y; break; } switch (d2) { case 0: v2 = (de) ? st->egridx-x : st->gridx-x; break; case 1: v2 = y; break; case 2: v2 = x; break; default: v2 = (de) ? st->egridy-y : st->gridy-y; break; } r = (de) ? (st->dline[st->li].hv) ? (v1+10000)*pn : (v2+10000)*-pn : (st->eline[st->li].hv) ? (v1+10000)*pn : (v2+10000)*-pn; return(r); } static int _getdeo(struct state *st, int x, int y, int map, int de) { int cr; switch(map) { case 0: /* horizontal one side */ return(x); case 1: /* vertical one side */ return(y); case 2: /* horizontal two side */ return(_min(x,st->gridx-x)+1); case 3: /* vertical two side */ return(_min(y,st->gridy-y)+1); case 4: /* square */ return(_max(abs(x-st->rx3[de]),abs(y-st->ry3[de]))+1); case 5: /* two squares */ return(_min(_max(abs(x-(st->rx3[de]/2)),abs(y-st->ry3[de])),_max(abs(x-(st->gridx-(st->rx2[de]/2))),abs(y-st->ry2[de])))+1); case 6: /* horizontal rectangle */ return(_max(abs(x-st->rx3[de]),abs(y-(st->ry3[de]))*st->cs1[de])+1); case 7: /* vertical rectangle */ return(_max(abs(x-st->rx3[de])*st->cs1[de],abs(y-(st->ry3[de])))+1); case 8: /* + cross */ return(_min(abs(x-st->rx3[de]),abs(y-(st->ry3[de])))+1); case 9: /* diagonal */ return((x*3/4+y)+1); case 10: /* opposite diagonal */ return((x*3/4+st->gridy-y)+1); case 11: /* diamond */ return((abs(x-st->rx3[de])+abs(y-st->ry3[de]))/2+1); case 12: /* two diamonds */ return(_min(abs(x-(st->rx3[de]/2))+abs(y-st->ry3[de]),abs(x-(st->gridx-(st->rx2[de]/2)))+abs(y-st->ry2[de]))/2+1); case 13: /* circle */ return(_dist(st,x,st->rx3[de],y,st->ry3[de],0)+1); case 14: /* horizontal ellipse */ return(_dist(st,x,st->rx3[de],y,st->ry3[de],1)+1); case 15: /* vertical ellipse */ return(_dist(st,x,st->rx3[de],y,st->ry3[de],2)+1); case 16: /* two circles */ return(_min(_dist(st,x,st->rx3[de]/2,y,st->ry3[de],0),_dist(st,x,st->gridx-(st->rx2[de]/2),y,st->ry2[de],0))+1); case 17: /* horizontal straight wave */ return(x+_wave(st,st->gridy+y,st->csw[0]*st->cs1[0],st->csw[0]*st->cs2[0],st->wave[de])); case 18: /* vertical straight wave */ return(y+_wave(st,st->gridx+x,st->csw[0]*st->cs1[0],st->csw[0]*st->cs2[0],st->wave[de])); case 19: /* horizontal wavey wave */ return(x+_wave(st,st->gridy+y+((x/5)*st->edir),st->csw[de]*st->cs1[de],st->csw[de]*st->cs2[de],st->wave[de])+1); case 20: /* vertical wavey wave */ return(y+_wave(st,st->gridx+x+((y/5)*st->edir),st->csw[de]*st->cs1[de],st->csw[de]*st->cs2[de],st->wave[de])+1); /* no d3d for 21,22 */ case 21: /* simultaneous directional */ return(_hv(st,x,y,st->cs1[0]%2,st->cs2[0]%2,1,de)); case 22: /* reverse directional */ return(_hv(st,x,y,st->cs1[0]%2,st->cs2[0]%2,-1,de)); case 23: /* length */ if (de) return(st->dline[st->li].len*1000+random()%5000); else return(st->eline[st->li].len*1000+random()%5000); case 24: /* object */ case 25: case 26: case 27: if (de) return(st->dline[st->li].obj*100); else return(st->eline[st->li].obj*100); default: /* color */ cr = (de) ? st->dline[st->li].color : st->eline[st->li].color; if (map<34) cr=st->rco[cr]; if ((map%6<4) || (de)) { /* by color */ cr*=1000; cr+=random()%1000; } else if (map%6==4) { /* by color horizontaly */ cr*=st->gridx; cr+=(x+random()%(st->gridx/2)); } else { /* by color vertically */ cr*=st->gridy; cr+=(y+random()%(st->gridy/2)); } return(cr); } return(1); } static void _init_screen(struct state *st) { int nstr, x; struct lineStruct *tmp; /* malloc memory in case of resize */ if (st->resized) { st->max_wxh=st->xgwa.width*st->xgwa.height; if (st->dline!=NULL) free(st->dline); if (st->eline!=NULL) free(st->eline); if (st->grid!=NULL) free(st->grid); if (st->zlist!=NULL) free(st->zlist); if (st->fdol!=NULL) free(st->fdol); if (st->odi!=NULL) free(st->odi); st->narray = (st->xgwa.width+1)*(st->xgwa.height+1)/4+1; st->dline = calloc(st->narray, sizeof(struct lineStruct)); st->eline = calloc(st->narray, sizeof(struct lineStruct)); st->grid = calloc(st->narray, sizeof(struct gridStruct)); st->zlist = calloc(st->narray, sizeof(unsigned int)); st->fdol = calloc(st->narray, sizeof(unsigned int)); st->odi = calloc(st->narray, sizeof(Bool)); if ((st->dline == NULL) || (st->eline == NULL) || (st->grid == NULL) || (st->zlist == NULL) || (st->fdol == NULL) || (st->odi == NULL)) { fprintf(stderr, "not enough memory\n"); exit(1); } st->dialog = (st->xgwa.width<500) ? 1 : 0; st->resized=False; } if (st->ii) { /* swap st->dline and st->eline pointers to resort and erase */ tmp=st->eline; st->eline=st->dline; st->dline=tmp; st->eli=st->li; st->elwid=st->lwid; st->elpu=st->lpu; st->egridx=st->gridx; st->egridy=st->gridy; /* create new erase order */ for (st->li=1; st->li<=st->eli; st->li++) st->eline[st->li].deo=(_getdeo(st,st->eline[st->li].x,st->eline[st->li].y,st->emap,0) + (random()%st->evar) + (random()%st->evar))*st->edir; qsort(st->eline, st->eli+1, sizeof(struct lineStruct), _comparedeo); } st->ii++; /* clear arrays and other counters */ st->di=st->ei=st->fi=st->li=st->oi=st->zi=0; st->grid_full=False; /* li starts from 1 */ st->dline[0].x=st->dline[0].y=st->dline[0].len=0; /* to keep it first after sorting so di is never null */ st->dline[0].deo=-999999999; /* set random screen variables */ st->lwid = (st->ii==1) ? 3 : 2+((random()%6)%4); st->d3d = ((st->tile==TILE_FLAT) || (st->tile==TILE_THIN) || (st->tile==TILE_OUTLINE)) ? D3D_NONE : (st->tile==TILE_BLOCK) ? D3D_BLOCK : (st->tile==TILE_NEON) ? D3D_NEON : (st->tile==TILE_TILED) ? D3D_TILED : /* force TILE_D3D on first screen to properly load all shades */ ((st->ii==1) && (!st->newcols)) ? D3D_TILED : (random()%5)%4; /* st->d3d=D3D_BLOCK; st->lwid=2; */ st->outline = (st->tile==TILE_OUTLINE) ? 1 : ((st->tile!=TILE_RANDOM) || (random()%5)) ? 0 : 1; st->round = (st->d3d==D3D_NEON) ? 1 : ((st->d3d==D3D_BLOCK) || (st->outline) || (random()%6)) ? 0 : 1; if ((st->d3d) || (st->outline) || (st->round)) st->lwid+=2; if ((!st->d3d) && (!st->round) && (!st->outline) && (st->lwid>3)) st->lwid-=2; if (st->d3d==D3D_TILED) st->lwid++; if (st->tile==TILE_THIN) st->lwid=2; _init_zlist(st); st->maxlen=(st->lwid>6) ? 2+(random()%4) : (st->lwid>4) ? 2+(random()%8)%6 : (st->lwid>2) ? 2+(random()%12)%8 : 2+(random()%15)%10; st->bnratio = 4+(random()%4)+(random()%4); st->forcemax = (random()%6) ? 0 : 1; if ((st->ii==1) || (st->newcols)) _init_colors(st); st->dmap = (st->emap+5+(random()%5))%DRAWORDERS; st->dmap=20+random()%20; st->dvar = (st->dmap>22) ? 100 : 10+(st->csw[0]*(random()%5)); st->ddir= (random()%2) ? 1 : -1; st->emap = (st->dmap+10+(random()%10))%20; st->evar = (st->emap>22) ? 100 : 10+(st->csw[0]*(random()%5)); st->edir= (random()%2) ? 1 : -1; st->layers= (random()%2) ? 2 : (random()%2) ? 1 : (random()%2) ? 3 : 4; st->cmap=(st->cmap+5+(random()%10))%COLORMAPS; for (x=0; xpattern[x]=random()%PATTERNS; st->shape[x]=random()%SHAPES; st->mix[x]=random()%20; nstr = (st->lwid==2) ? 20+random()%12 : (st->lwid==3) ? 16+random()%8 : (st->lwid==4) ? 12+random()%6 : (st->lwid==5) ? 10+random()%5 : (st->lwid==6) ? 8+random()%4 : 5+random()%5; st->csw[x] = _max(5,st->gridy/nstr); st->wsx[x] = (st->wsx[x]+3+(random()%3))%STRETCHES; st->wsy[x] = (st->wsy[x]+3+(random()%3))%STRETCHES; st->sec[x] = random()%5; if ((!st->dialog) && (st->sec[x]<2)) st->csw[x]/=2; st->cs1[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; st->cs2[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; st->cs3[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; st->cs4[x] = (st->dialog) ? 1+random()%3 : 2+random()%5; st->wave[x]=random()%WAVES; st->wavel[x]=st->csw[x]*(2+random()%6); st->waveh[x]=st->csw[x]*(1+random()%3); st->rx1[x]=(st->gridx/10+random()%(st->gridx*8/10)); st->ry1[x]=(st->gridy/10+random()%(st->gridy*8/10)); st->rx2[x]=(st->gridx*2/10+random()%(st->gridx*6/10)); st->ry2[x]=(st->gridy*2/10+random()%(st->gridy*6/10)); st->rx3[x]=(st->gridx*3/10+random()%(st->gridx*4/10)); st->ry3[x]=(st->gridy*3/10+random()%(st->gridy*4/10)); } } static int _shape(struct state *st, int x, int y, int rx, int ry, int n) { switch(st->shape[n]) { case 0: /* square/rectangle */ case 1: case 2: return(1+_max(abs(x-rx)*st->cs1[n]/st->cs2[n],abs(y-ry)*st->cs3[n]/st->cs4[n])); case 3: /* diamond */ case 4: return(1+(abs(x-rx)*st->cs1[n]/st->cs2[n]+abs(y-ry)*st->cs3[n]/st->cs4[n])); case 5: /* 8 point star */ return(1+_min(_max(abs(x-rx),abs(y-ry))*3/2,abs(x-rx)+abs(y-ry))); case 6: /* circle/oval */ case 7: case 8: return(1+_dist(st,x,rx,y,ry,st->cs1[n])); case 9: /* black hole circle */ return(1+(st->gridx*st->gridy/(1+(_dist(st,x,rx,y,ry,st->cs2[n]))))); case 10: /* sun */ return(1+_min(abs(x-rx)*st->gridx/(abs(y-ry)+1),abs(y-ry)*st->gridx/(abs(x-rx)+1))); case 11: /* 2 circles+inverted circle */ return(1+(_dist(st,x,rx,y,ry,st->cs1[n])*_dist(st,x,(rx*3)%st->gridx,y,(ry*5)%st->gridy,st->cs1[n])/(1+_dist(st,x,(rx*4)%st->gridx,y,(ry*7)%st->gridy,st->cs1[n])))); case 12: /* star */ return(1+(int)sqrt(abs((x-rx)*(y-ry)))); case 13: /* centered ellipse */ return(1+_dist(st,x,rx,y,ry,0)+_dist(st,x,st->gridx-rx,y,st->gridy-ry,0)); default: /* triangle */ return(1+_triangle(st,x,y,rx,ry,st->cs4[n])); } return(1+_triangle(st,x,y,rx,ry,st->cs4[n])); } static int _pattern(struct state *st, int x, int y, int n) { int v=0, ox; ox=x; switch(st->wsx[n]) { case 0: /* slants */ x+=y/(1+st->cs4[n]); break; case 1: x+=(st->gridy-y)/(1+st->cs4[n]); break; case 2: /* curves */ x+=_wave(st,y,st->gridx/(1+st->cs1[n]),st->gridy,0); break; case 3: x+=_wave(st,st->gridy-y,st->gridy/(1+st->cs1[n]),st->gridy,0); break; case 4: /* U curves */ x+=_wave(st,y,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); break; case 5: x-=_wave(st,y,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); break; } switch(st->wsy[0]) { case 0: /* slants */ y+=ox/(1+st->cs1[n]); break; case 1: y+=(st->gridx-ox)/(1+st->cs1[n]); break; case 2: /* curves */ y+=_wave(st,ox,st->gridx/(1+st->cs1[n]),st->gridx,0); break; case 3: y+=_wave(st,st->gridx-ox,st->gridx/(1+st->cs1[n]),st->gridx,0); break; case 4: /* U curves */ y+=_wave(st,ox,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); break; case 5: y-=_wave(st,ox,st->cs1[n]*st->csw[n]/2,st->gridy*2/M_PI,0); break; } switch(st->pattern[n]) { case 0: /* horizontal stripes */ v=y; break; case 1: /* vertical stripes */ v=x; break; case 2: /* diagonal stripes */ v=(x+(y*st->cs1[n]/st->cs2[n])); break; case 3: /* reverse diagonal stripes */ v=(x-(y*st->cs1[n]/st->cs2[n])); break; case 4: /* checkerboard */ v=(y/st->csw[n]*3+x/st->csw[n])*st->csw[n]; break; case 5: /* diagonal checkerboard */ v=((x+y)/2/st->csw[n]+(x+st->gridy-y)/2/st->csw[n]*3)*st->csw[n]; break; case 6: /* + cross */ v=st->gridx+(_min(abs(x-st->rx3[n]),abs(y-st->ry3[n]))*2); break; case 7: /* double + cross */ v=_min(_min(abs(x-st->rx2[n]),abs(y-st->ry2[n])),_min(abs(x-st->rx1[n]),abs(y-st->ry1[n])))*2; break; case 8: /* X cross */ v=st->gridx+(_min(abs(x-st->rx3[n])*st->cs1[n]/st->cs2[n]+abs(y-st->ry2[n])*st->cs3[n]/st->cs4[n],abs(x-st->rx3[n])*st->cs1[n]/st->cs2[n]-abs(y-st->ry3[n])*st->cs3[n]/st->cs4[n])*2); break; case 9: /* double X cross */ v=_min(_min(abs(x-st->rx2[n])+abs(y-st->ry2[n]),abs(x-st->rx2[n])-abs(y-st->ry2[n])),_min(abs(x-st->rx1[n])+abs(y-st->ry1[n]),abs(x-st->rx1[n])-abs(y-st->ry1[n])))*2; break; case 10: /* horizontal stripes/waves */ v=st->gridy+(y+_wave(st,x,st->waveh[n],st->wavel[n],st->wave[n])); break; case 11: /* vertical stripes/waves */ v=st->gridx+(x+_wave(st,y,st->waveh[n],st->wavel[n],st->wave[n])); break; case 12: /* diagonal stripes/waves */ v=st->gridx+(x+(y*st->cs1[n]/st->cs2[n])+_wave(st,x,st->waveh[n],st->wavel[n],st->wave[n])); break; case 13: /* diagonal stripes/waves */ v=st->gridx+(x-(y*st->cs1[n]/st->cs2[n])+_wave(st,y,st->waveh[n],st->wavel[n],st->wave[n])); break; case 14: /* horizontal spikey waves */ v=y+(st->csw[n]*st->cs4[n]/st->cs3[n])+_wave(st,x+((y/st->cs3[n])*st->edir),st->csw[n]/2*st->cs1[n]/st->cs2[n],st->csw[n]/2*st->cs2[n]/st->cs1[n],st->wave[n]); break; case 15: /* vertical spikey waves */ v=x+(st->csw[n]*st->cs1[n]/st->cs2[n])+_wave(st,y+((x/st->cs3[n])*st->edir),st->csw[n]/2*st->cs1[n]/st->cs2[n],st->csw[n]/2*st->cs3[n]/st->cs4[n],st->wave[n]); break; case 16: /* big slanted hwaves */ v=st->gridy-y-(x*st->cs1[n]/st->cs3[n])+(st->csw[n]*st->cs1[n]*st->cs2[n]) +_wave(st,x,st->csw[n]/3*st->cs1[n]*st->cs2[n],st->csw[n]/3*st->cs3[n]*st->cs2[n],st->wave[n]); break; case 17: /* big slanted vwaves */ v=x-(y*st->cs1[n]/st->cs3[n])+(st->csw[n]*st->cs1[n]*st->cs2[n]) +_wave(st,y, st->csw[n]/3*st->cs1[n]*st->cs2[n], st->csw[n]/3*st->cs3[n]*st->cs2[n], st->wave[n]); break; case 18: /* double hwave */ v=y+(y+st->csw[n]*st->cs3[n])+_wave(st,x,st->csw[n]/3*st->cs3[n],st->csw[n]/3*st->cs2[n],st->wave[n])+_wave(st,x,st->csw[n]/3*st->cs4[n],st->csw[n]/3*st->cs1[n]*3/2,st->wave[n]); break; case 19: /* double vwave */ v=x+(x+st->csw[n]*st->cs1[n])+_wave(st,y,st->csw[n]/3*st->cs1[n],st->csw[n]/3*st->cs3[n],st->wave[n])+_wave(st,y,st->csw[n]/3*st->cs2[n],st->csw[n]/3*st->cs4[n]*3/2,st->wave[n]); break; case 20: /* one shape */ case 21: case 22: v=_shape(st,x, y, st->rx3[n], st->ry3[n], n); break; case 23: /* two shapes */ case 24: case 25: v=_min(_shape(st,x, y, st->rx1[n], st->ry1[n], n),_shape(st,x, y, st->rx2[n], st->ry2[n], n)); break; case 26: /* two shapes opposites */ case 27: v=_min(_shape(st,x, y, st->rx2[n], st->ry2[n], n),_shape(st,x, y, st->gridx-st->rx2[n], st->gridy-st->rx2[n], n)); break; case 28: /* two shape checkerboard */ case 29: v=((_shape(st,x, y, st->rx1[n], st->ry1[n], n)/st->csw[n])+(_shape(st,x, y, st->rx2[n], st->ry2[n], n)/st->csw[n]))*st->csw[n]; break; case 30: /* two shape blob */ case 31: v=(_shape(st,x, y, st->rx1[n], st->ry1[n], n)+_shape(st,x, y, st->rx2[n], st->ry2[n], n))/2; break; case 32: /* inverted two shape blob */ case 33: v=(_shape(st,x, y, st->rx1[n], st->ry1[n], n)+_shape(st,st->gridx-x, st->gridy-y, st->rx1[n], st->ry1[n], n))/2; break; case 34: /* three shapes */ case 35: v=_min(_shape(st,x, y, st->rx3[n], st->ry3[n], n),_min(_shape(st,x, y, st->rx1[n], st->ry1[n], n),_shape(st,x, y, st->rx2[n], st->ry2[n], n))); break; case 36: /* three shape blob */ case 37: v=(_shape(st,x, y, st->rx1[n], st->ry1[n], n)+_shape(st,x, y, st->rx2[n], st->ry2[n], n)+_shape(st,x, y, st->rx3[n], st->ry3[n], n))/3; break; case 38: /* 4 shapes */ v=(_min(_shape(st,x, y, st->rx2[n], st->ry2[n], n),_shape(st,x, y, st->gridx-st->rx2[n], st->gridy-st->ry2[n], n)),_min(_shape(st,x, y, st->gridx-st->rx2[n], st->ry2[n], n),_shape(st,x, y, st->rx2[n], st->gridy-st->ry2[n], n))); break; case 39: /* four rainbows */ v=(_min(_shape(st,x, y, st->gridx-st->rx2[n]/2, st->csw[n], n),_shape(st,x, y, st->csw[n], st->ry2[n]/2, n)),_min(_shape(st,x, y, st->rx2[n]/2, st->gridy-st->csw[n], n),_shape(st,x, y, st->gridx-st->csw[n], st->gridy-(st->ry2[n]/2), n))); break; } /* stretch or contract stripe */ switch(st->sec[n]) { case 0: v=(int)sqrt((int)sqrt(abs(v)*st->gridx)*st->gridx); break; case 1: v=((int)pow(v,2)/st->gridx); break; } return (abs(v)); } static int _getcolor(struct state *st, int x, int y) { int n, cv[LAYERS]; cv[0] = 0; for (n=0; nlayers; n++) { cv[n]=_pattern(st,x,y,n); /* first wave/shape */ cv[0] = (!n) ? cv[0]/st->csw[0] : /* checkerboard+1 */ (st->mix[n]<5) ? (cv[0]*st->csw[0]+cv[n])/st->csw[n] : /* checkerboard+ncol/2 */ (st->mix[n]<12) ? cv[0]+(cv[n]/st->csw[n]*st->ncolors/2) : /* add mix */ (st->mix[n]<16) ? cv[0]+(cv[n]/st->csw[n]) : /* subtract mix */ (st->mix[n]<18) ? cv[0]-(cv[n]/st->csw[n]) : /* r to l morph mix */ (st->mix[n]==18) ? ((cv[0]*x)+(cv[n]*(st->gridx-x)/st->csw[n]))/st->gridx : /* u to d morph mix */ ((cv[0]*y)+(cv[n]*(st->gridy-y)/st->csw[n]))/st->gridy; } return(cv[0]); } /* return value=line direction st->olen=open space to edge or next blocking line st->bln=blocking line number or -1 if edge blocks */ static int _findopen(struct state *st, int x, int y, int z) { int dir, od[4], no=0; if (((st->grid[z].hl) || (st->grid[z].hr)) && ((st->grid[z].vu) || (st->grid[z].vd))) return(DIR_NONE); if ((z>st->gridx) && (!st->grid[z].hl) && (!st->grid[z].hr) && (!st->grid[z-st->gridx].line)) { od[no]=DIR_UP; no++; } if ((zgridn-st->gridx) && (!st->grid[z].hl) && (!st->grid[z].hr) && (!st->grid[z+st->gridx].line)) { od[no]=DIR_DOWN; no++; } if ((x) && (!st->grid[z].hl) && (!st->grid[z].hr) && (!st->grid[z-1].line)) { od[no]=DIR_LEFT; no++; } if (((z+1)%st->gridx) && (!st->grid[z].hl) && (!st->grid[z].hr) && (!st->grid[z+1].line)) { od[no]=DIR_RIGHT; no++; } if (!no) return(DIR_NONE); dir=od[random()%no]; st->olen=st->bln=0; while ((st->olen<=st->maxlen) && (!st->bln)) { st->olen++; if (dir==DIR_UP) st->bln = (y-st->olen<0) ? -1 : st->grid[z-(st->olen*st->gridx)].line; if (dir==DIR_DOWN) st->bln = (y+st->olen>=st->gridy) ? -1 : st->grid[z+(st->olen*st->gridx)].line; if (dir==DIR_LEFT) st->bln = (x-st->olen<0) ? -1 : st->grid[z-st->olen].line; if (dir==DIR_RIGHT) st->bln = (x+st->olen>=st->gridx) ? -1 : st->grid[z+st->olen].line; } st->olen--; return(dir); } static void _fillgrid(struct state *st) { unsigned int gridc, n, add; gridc=st->gridx*st->dline[st->li].y+st->dline[st->li].x; add = (st->dline[st->li].hv) ? 1 : st->gridx; for (n=0; n<=st->dline[st->li].len; n++) { if (n) gridc+=add; if (!st->grid[gridc].line) { st->fi++; st->grid[gridc].line=st->li; } if (st->dline[st->li].hv) { if (n) st->grid[gridc].hr=st->li; if (ndline[st->li].len) st->grid[gridc].hl=st->li; } else { if (n) st->grid[gridc].vd=st->li; if (ndline[st->li].len) st->grid[gridc].vu=st->li; } if (st->fi>=st->gridn) { st->grid_full=True; return; } } } static void _newline(struct state *st) { int bl, bz, dir, lt, x, y, z; bl=0; z=st->zlist[st->zi]; x=z%st->gridx; y=z/st->gridx; st->zi++; dir=_findopen(st,x,y,z); if (!st->grid[z].line) { /* this is an empty space, make a new line unless nothing is open around it */ if (dir==DIR_NONE) { /* nothing is open, force a len 1 branch in any direction */ lt=LINE_FORCE; while ((dir==DIR_NONE) || ((dir==DIR_UP) && (!y)) || ((dir==DIR_DOWN) && (y+1==st->gridy)) || ((dir==DIR_LEFT) && (!x)) || ((dir==DIR_RIGHT) && (x+1==st->gridx))) { dir=random()%4; } bz = (dir==DIR_UP) ? z-st->gridx : (dir==DIR_DOWN) ? z+st->gridx : (dir==DIR_LEFT) ? z-1 : z+1; bl = st->grid[bz].line; } else if ((st->bnratio>1) && (st->bln>0) && (st->olenmaxlen) && (random()%st->bnratio)) { /* branch into blocking line */ lt=LINE_BRIN; bl = st->bln; } else { /* make a new line and new object */ lt=LINE_NEW; st->oi++; } } else { /* this is a filled space, make a branch unless nothing is open around it */ if (dir==DIR_NONE) return; /* make a branch out of this line */ lt=LINE_BROUT; bl=st->grid[z].line; } st->li++; st->dline[st->li].len = (lt==LINE_FORCE) ? 1 : (lt==LINE_BRIN) ? st->olen+1 : (!st->forcemax) ? st->olen : 1+random()%st->olen; st->dline[st->li].x=x; if (dir==DIR_LEFT) st->dline[st->li].x-=st->dline[st->li].len; st->dline[st->li].y=y; if (dir==DIR_UP) st->dline[st->li].y-=st->dline[st->li].len; st->dline[st->li].hv = ((dir==DIR_LEFT) || (dir==DIR_RIGHT)) ? True : False; st->dline[st->li].obj = (lt==LINE_NEW) ? st->oi : st->dline[bl].obj; if (lt==LINE_NEW) { int color = (_getcolor(st,x,y))%st->ncolors; if (color < 0) color += st->ncolors; st->dline[st->li].color = color; } else { st->dline[st->li].color = st->dline[bl].color; } st->dline[st->li].deo=(_getdeo(st,x,y,st->dmap,1) + (random()%st->dvar) + (random()%st->dvar))*st->ddir; st->dline[st->li].ndol=0; _fillgrid(st); } static void _create_screen(struct state *st) { while(!st->grid_full) _newline(st); qsort(st->dline, st->li+1, sizeof(struct lineStruct), _comparedeo); /*st->lpu=st->li/20/((6-st->speed)*3); Used to use a computed lpu, lines per update to control draw speed draw 1/lpu of the lines before each XSync which takes a split second the higher the lpu, the quicker the screen draws. This worked somewhat after the 4->5 update, however with the Mac updating so much more slowly, values tuned for it draw the screen in a blink on Linux. Therefore we draw 1/200th of the screen with each update and sleep, if necessary */ st->lpu = (st->dialog) ? st->li/50 : st->li/200; if (!st->lpu) st->lpu = 1; st->bi=1; st->mode=MODE_ERASE; } static void _fill_outline(struct state *st, int di) { int x, y, h, w; if (!di) return; x=st->dline[di].x*st->lwid+1; y=st->dline[di].y*st->lwid+1; if (st->dline[di].hv) { w=(st->dline[di].len+1)*st->lwid-3; h=st->lwid-3; } else { w=st->lwid-3; h=(st->dline[di].len+1)*st->lwid-3; } XFillRectangle (st->display, st->window, st->bgc, x, y, w, h); } static void _XFillRectangle(struct state *st, int di, int adj) { int a, b, x, y, w, h; x=st->dline[di].x*st->lwid; y=st->dline[di].y*st->lwid; if (st->dline[di].hv) { w=(st->dline[di].len+1)*st->lwid-1; h=st->lwid-1; } else { w=st->lwid-1; h=(st->dline[di].len+1)*st->lwid-1; } switch (st->d3d) { case D3D_NEON: x+=adj; y+=adj; w-=adj*2; h-=adj*2; break; case D3D_BLOCK: x+=adj; y+=adj; w-=st->lwid/2-1; h-=st->lwid/2-1; break; } if (!st->round) { XFillRectangle(st->display, st->window, st->fgc, x, y, w, h); } else { if (hlwid) { /* horizontal */ a=(h-1)/2; for (b=0; b<=a; b++) XFillRectangle(st->display, st->window, st->fgc, x+b, y+a-b, w-b*2, h-((a-b)*2)); } else { /* vertical */ a=(w-1)/2; for (b=0; b<=a; b++) XFillRectangle(st->display, st->window, st->fgc, x+a-b, y+b, w-((a-b)*2), h-b*2); } } } static void _XFillTriangle(struct state *st, int color, int x1, int y1, int x2, int y2, int x3, int y3) { XPoint points[3]; points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x3; points[2].y=y3; XSetForeground(st->display, st->fgc, st->colors[color].pixel); XFillPolygon (st->display, st->window, st->fgc, points, 3, Convex, CoordModeOrigin); } static void _XFillPolygon4(struct state *st, int color, int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { XPoint points[4]; points[0].x=x1; points[0].y=y1; points[1].x=x2; points[1].y=y2; points[2].x=x3; points[2].y=y3; points[3].x=x4; points[3].y=y4; XSetForeground(st->display, st->fgc, st->colors[color].pixel); XFillPolygon (st->display, st->window, st->fgc, points, 4, Convex, CoordModeOrigin); } static void _draw_tiled(struct state *st, int color) { int a, c, d, x, y, z, m1, m2, lr, nl, w, h; a = (st->dline[st->di].hv) ? 1 : st->gridx; z = st->dline[st->di].y*st->gridx+st->dline[st->di].x; m1 = (st->lwid-1)/2; m2 = st->lwid/2; lr = st->lwid-1; nl = st->lwid; /* draw tiles one grid cell at a time */ for (c=0; c<=st->dline[st->di].len; c++) { if (st->dline[st->di].hv) { x = (st->dline[st->di].x+c)*st->lwid; y = st->dline[st->di].y*st->lwid; if (c) st->grid[z].dhr=st->di; if (cdline[st->di].len) st->grid[z].dhl=st->di; } else { x = st->dline[st->di].x*st->lwid; y = (st->dline[st->di].y+c)*st->lwid; if (c) st->grid[z].dvd=st->di; if (cdline[st->di].len) st->grid[z].dvu=st->di; } d=0; if (st->grid[z].dhl) d+=8; if (st->grid[z].dhr) d+=4; if (st->grid[z].dvu) d+=2; if (st->grid[z].dvd) d++; /* draw line base */ switch (d) { case 1: case 2: /* vertical */ case 3: case 5: case 6: case 7: case 11: case 15: h = ((d==1) || (d==5)) ? lr : nl; XSetForeground(st->display, st->fgc, st->colors[color].pixel); XFillRectangle (st->display, st->window, st->fgc, x, y, m2, h); XSetForeground(st->display, st->fgc, st->colors[color+3].pixel); XFillRectangle (st->display, st->window, st->fgc, x+m2, y, m1, h); break; case 4: case 8: /* horizontal */ case 9: case 10: case 12: case 13: case 14: w = (d==4) ? lr : nl; XSetForeground(st->display, st->fgc, st->colors[color+1].pixel); XFillRectangle (st->display, st->window, st->fgc, x, y, w, m2); XSetForeground(st->display, st->fgc, st->colors[color+2].pixel); XFillRectangle (st->display, st->window, st->fgc, x, y+m2, w, m1); break; } /* draw angles */ switch(d) { case 1: /* bottom end ^ */ _XFillTriangle(st,color+2, x, y+lr, x+lr, y+lr, x+m2, y+m2); break; case 2: /* top end \/ */ _XFillTriangle(st,color+1, x, y, x+lr, y, x+m2, y+m2); break; case 4: /* right end < */ _XFillTriangle(st,color+3, x+lr, y, x+lr, y+lr, x+m2, y+m2); break; case 5: /* LR corner */ _XFillTriangle(st,color+1, x, y+m2, x+m2, y+m2, x, y); _XFillPolygon4(st,color+2, x, y+m2, x+m2, y+m2, x+lr, y+lr, x, y+lr); break; case 6: /* UR corner */ _XFillPolygon4(st,color+1, x, y+m2, x+m2, y+m2, x+lr, y, x, y); _XFillTriangle(st,color+2, x, y+m2, x+m2, y+m2, x, y+lr); break; case 7: /* T > into line */ _XFillTriangle(st,color+1, x, y+m2, x+m2, y+m2, x, y); _XFillTriangle(st,color+2, x, y+m2, x+m2, y+m2, x, y+lr); break; case 8: /* left end > */ _XFillTriangle(st,color, x, y, x, y+lr, x+m2, y+m2); break; case 9: /* LL corner */ _XFillPolygon4(st,color, x+m2, y, x+m2, y+m2, x, y+lr, x, y); _XFillTriangle(st,color+3, x+m2, y, x+m2, y+m2, x+lr, y); break; case 10: /* UL corner */ _XFillPolygon4(st,color, x+m2, y+nl, x+m2, y+m2, x, y, x, y+nl); _XFillPolygon4(st,color+3, x+m2, y+nl, x+m2, y+m2, x+lr, y+lr, x+lr, y+nl); break; case 11: /* T < into line */ _XFillPolygon4(st,color+1, x+nl, y+m2, x+m2, y+m2, x+lr, y, x+nl, y); _XFillPolygon4(st,color+2, x+nl, y+m2, x+m2, y+m2, x+lr, y+lr, x+nl, y+lr); break; case 13: /* T \/ into line */ _XFillTriangle(st,color, x+m2, y, x+m2, y+m2, x, y); _XFillTriangle(st,color+3, x+m2, y, x+m2, y+m2, x+lr, y); break; case 14: /* T ^ into line */ _XFillPolygon4(st,color, x+m2, y+nl, x+m2, y+m2, x, y+lr, x, y+nl); _XFillPolygon4(st,color+3, x+m2, y+nl, x+m2, y+m2, x+lr, y+lr, x+lr, y+nl); break; case 15: /* X intersection */ _XFillTriangle(st,color+1, x, y+m2, x+m2, y+m2, x, y); _XFillTriangle(st,color+2, x, y+m2, x+m2, y+m2, x, y+lr); _XFillPolygon4(st,color+1, x+nl, y+m2, x+m2, y+m2, x+lr, y, x+nl, y); _XFillPolygon4(st,color+2, x+nl, y+m2, x+m2, y+m2, x+lr, y+lr, x+nl, y+lr); break; } z+=a; } } static long _mselapsed(struct state *st) { struct timeval t; gettimeofday(&t, NULL); t.tv_sec -= st->time.tv_sec; t.tv_usec -= st->time.tv_usec; return ((long)t.tv_sec*1000000+t.tv_usec); } static void _draw_lines(struct state *st) { int n, z, a, color, sh, di; if (st->bi==1) for (a=0; a<=st->oi; a++) st->fdol[a]=0; for (st->di=st->bi; st->di<_min(st->li+1,st->bi+st->lpu); st->di++) { color=(st->dline[st->di].color%st->ncolors)*st->shades; XSetForeground(st->display, st->fgc, st->colors[color].pixel); switch (st->d3d) { case D3D_NEON: st->dline[st->di].ndol=st->fdol[st->dline[st->di].obj]; st->fdol[st->dline[st->di].obj]=st->di; for (sh=0; shlwid/2; sh++) { XSetForeground(st->display, st->fgc, st->colors[color+sh].pixel); di=st->di; while(di>0) { _XFillRectangle(st,di,sh); di=st->dline[di].ndol; } } break; case D3D_BLOCK: st->dline[st->di].ndol=st->fdol[st->dline[st->di].obj]; st->fdol[st->dline[st->di].obj]=st->di; for (sh=0; shlwid/2; sh++) { XSetForeground(st->display, st->fgc, st->colors[color+(st->lwid/2)-sh-1].pixel); di=st->di; while(di>0) { _XFillRectangle(st,di,sh); di=st->dline[di].ndol; } } break; case D3D_TILED: _draw_tiled(st,color); break; default: /* D3D_NONE */ _XFillRectangle(st,st->di,0); if (st->outline) { _fill_outline(st, st->di); z=st->dline[st->di].y*st->gridx+st->dline[st->di].x; a = (st->dline[st->di].hv) ? 1 : st->gridx; for (n=0; n<=st->dline[st->di].len; n++) { _fill_outline(st, st->grid[z].dhl); _fill_outline(st, st->grid[z].dhr); _fill_outline(st, st->grid[z].dvu); _fill_outline(st, st->grid[z].dvd); if (st->dline[st->di].hv) { if (n) st->grid[z].dhr=st->di; if (ndline[st->di].len) st->grid[z].dhl=st->di; } else { if (n) st->grid[z].dvd=st->di; if (ndline[st->di].len) st->grid[z].dvu=st->di; } z+=a; } } break; } } if (st->di>st->li) { st->bi=1; st->mode=MODE_CREATE; } else { st->bi+=st->lpu; } } static void _erase_lines(struct state *st) { if (!st->ii) return; for (st->di=st->bi; st->di<_min(st->eli+1,st->bi+st->elpu); st->di++) { if (st->eline[st->di].hv) { XFillRectangle (st->display, st->window, st->bgc, st->eline[st->di].x*st->elwid, st->eline[st->di].y*st->elwid, (st->eline[st->di].len+1)*st->elwid, st->elwid); } else { XFillRectangle (st->display, st->window, st->bgc, st->eline[st->di].x*st->elwid, st->eline[st->di].y*st->elwid, st->elwid, (st->eline[st->di].len+1)*st->elwid); } if (st->di==st->eli) /* clear just in case */ XFillRectangle(st->display, st->window, st->bgc, 0, 0, st->xgwa.width, st->xgwa.height); } if (st->di>st->eli) { st->bi=1; if (st->resized) { st->mode=MODE_CREATE; } else { st->mode=MODE_DRAW; } } else { st->bi+=st->elpu; } } static void * abstractile_init(Display *display, Window window) { struct state *st = (struct state *) calloc (1, sizeof(*st)); XGCValues gcv; /* struct utsname os;*/ char *tile = get_string_resource(display, "tile", "Tile"); if (tile && !strcmp(tile, "random")) st->tile = TILE_RANDOM; else if (tile && !strcmp(tile, "flat")) st->tile = TILE_FLAT; else if (tile && !strcmp(tile, "thin")) st->tile = TILE_THIN; else if (tile && !strcmp(tile, "outline")) st->tile = TILE_OUTLINE; else if (tile && !strcmp(tile, "block")) st->tile = TILE_BLOCK; else if (tile && !strcmp(tile, "neon")) st->tile = TILE_NEON; else if (tile && !strcmp(tile, "tiled")) st->tile = TILE_TILED; else { if (tile && *tile && !!strcmp(tile, "random")) fprintf(stderr, "%s: unknown tile option %s\n", progname, tile); st->tile = TILE_RANDOM; } if (tile) free (tile); st->speed = get_integer_resource(display, "speed", "Integer"); if (st->speed < 0) st->speed = 0; if (st->speed > 5) st->speed = 5; st->sleep = get_integer_resource(display, "sleep", "Integer"); if (st->sleep < 0) st->sleep = 0; if (st->sleep > 60) st->sleep = 60; st->display=display; st->window=window; /* get screen size and create Graphics Contexts */ XGetWindowAttributes (display, window, &st->xgwa); gcv.foreground = get_pixel_resource(display, st->xgwa.colormap, "foreground", "Foreground"); st->fgc = XCreateGC (display, window, GCForeground, &gcv); gcv.foreground = get_pixel_resource(display, st->xgwa.colormap, "background", "Background"); st->bgc = XCreateGC (display, window, GCForeground, &gcv); /* Um, no. This is obscene. -jwz. uname(&os); st->newcols=((!strcmp(os.sysname,"Linux")) || (!strcmp(os.sysname,"Darwin"))) ? True : False; */ st->newcols=False; st->mode=MODE_CREATE; st->ii=0; st->resized=True; return st; } static unsigned long abstractile_draw (Display *dpy, Window window, void *closure) { struct state *st = (struct state *) closure; int mse, usleep; gettimeofday(&st->time, NULL); /* If the window is too small, do nothing, sorry! */ if (st->xgwa.width > 20 && st->xgwa.height > 20) { switch (st->mode) { case MODE_CREATE: _init_screen(st); _create_screen(st); break; case MODE_ERASE: _erase_lines(st); break; case MODE_DRAW: _draw_lines(st); break; } } mse=_mselapsed(st); usleep = ((!st->ii) && (st->mode==MODE_CREATE)) ? 0 : (st->mode==MODE_CREATE) ? st->sleep*1000000-mse : /* speed=0-5, goal is 10,8,6,4,2,0 sec normal and 5,4,3,2,1,0 dialog */ (5-st->speed)*(2-st->dialog)*100000/st->lpu-mse; if (usleep>=0) return usleep; return 0; } static void abstractile_reshape (Display *dpy, Window window, void *closure, unsigned int w, unsigned int h) { struct state *st = (struct state *) closure; st->xgwa.width = w; st->xgwa.height = h; if (w*h>st->max_wxh) st->resized=True; } static Bool abstractile_event (Display *dpy, Window window, void *closure, XEvent *event) { struct state *st = (struct state *) closure; if (screenhack_event_helper (dpy, window, event)) { st->mode=MODE_CREATE; return True; } return False; } static void abstractile_free (Display *dpy, Window window, void *closure) { struct state *st = (struct state *) closure; if (st->dline) free(st->dline); if (st->eline) free(st->eline); if (st->grid) free(st->grid); if (st->zlist) free(st->zlist); if (st->fdol) free(st->fdol); if (st->odi) free(st->odi); XFreeGC (dpy, st->fgc); XFreeGC (dpy, st->bgc); free (st); } static const char *abstractile_defaults [] = { ".background: black", ".foreground: white", "*fpsSolid: true", "*sleep: 3", "*speed: 3", "*tile: random", #ifdef HAVE_MOBILE "*ignoreRotation: True", #endif 0 }; static XrmOptionDescRec abstractile_options [] = { { "-sleep", ".sleep", XrmoptionSepArg, 0 }, { "-speed", ".speed", XrmoptionSepArg, 0 }, { "-tile", ".tile", XrmoptionSepArg, 0 }, { 0, 0, 0, 0 } }; XSCREENSAVER_MODULE ("Abstractile", abstractile)