1 /*Copyright © Chris Le Sueur (thefishface@gmail.com) February 2005
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 "Software"), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
22 Ultimate thanks go to Massimino Pascal, who created the original
23 xscreensaver hack, and inspired me with it's swirly goodness. This
24 version adds things like variable quality, number of functions and also
25 a groovier colouring mode.
35 #include "screenhack.h"
37 static float myrandom(float up)
39 return(((float)random()/RAND_MAX)*up);
46 static Bool notranslate, noscale, norotate;
67 int blackColor, whiteColor;
69 char *progclass = "IFS";
77 "*notranslate: False",
83 XrmOptionDescRec options [] = {
84 { "-detail", ".length", XrmoptionSepArg, 0 },
85 { "-delay", ".delay", XrmoptionSepArg, 0 },
86 { "-mode", ".mode", XrmoptionSepArg, 0 },
87 { "-colors", ".colors", XrmoptionSepArg, 0 },
88 { "-functions", ".lensnum", XrmoptionSepArg, 0 },
89 { "-notranslate", ".notranslate", XrmoptionNoArg, "True" },
90 { "-noscale", ".noscale", XrmoptionNoArg, "True" },
91 { "-norotate", ".norotate", XrmoptionNoArg, "True" },
95 /*Takes the average of two colours, with some nifty bit-shifting*/
96 static long blend(long c1, long c2)
98 long R1=(c1 & 0xFF0000) >> 16;
99 long R2=(c2 & 0xFF0000) >> 16;
100 long G1=(c1 & 0x00FF00) >> 8;
101 long G2=(c2 & 0x00FF00) >> 8;
102 long B1=(c1 & 0x0000FF);
103 long B2=(c2 & 0x0000FF);
105 return (((R1+R2)/2 << 16) | ((G1+G2)/2 << 8) | ((B1+B2)/2));
108 /*Draw a point on the backbuffer*/
109 static void sp(float x, float y, long c)
113 if(x<0 || x>=width || y<0 || y>=height) return;
114 XSetForeground(dpy, gc, c);
115 XDrawPoint(dpy, backbuffer, gc, (int)x, (int)y);
118 /*Copy backbuffer to front buffer and clear backbuffer*/
119 static void draw(void)
128 XSetForeground(dpy, gc, blackColor);
138 /*Rotation, Scale, Translation X & Y*/
139 float ra,raa,sa,txa,tya;
145 static void CreateLens(float nr,
152 newlens->ra=newlens->raa=newlens->sa=newlens->txa=newlens->tya=0;
153 if(!norotate) newlens->r=nr;
156 if(!noscale) newlens->s=ns;
170 static float stepx(float x, float y, Lens *l)
172 return l->s*cos(l->r)*x+l->s*sin(l->r)*y+l->tx;
175 static float stepy(float x, float y, Lens *l)
177 return l->s*sin(l->r)*-x+l->s*cos(l->r)*y+l->ty;
180 static void mutate(Lens *l)
183 l->raa+=myrandom(0.002)-0.001;
186 if(l->ra>0.07 || l->ra<-0.07) l->ra/=1.4;
187 if(l->raa>0.005 || l->raa<-0.005) l->raa/=1.2;
190 l->sa+=myrandom(0.01)-0.005;
192 if(l->s>0.4) l->sa -=0.004;
193 if(l->s<-0.4) l->sa +=0.004;
194 if(l->sa>0.07 || l->sa<-0.07) l->sa/=1.4;
197 l->txa+=myrandom(0.004)-0.002;
198 l->tya+=myrandom(0.004)-0.002;
201 if(l->tx>6) l->txa-=0.004;
202 if(l->ty>6) l->tya-=0.004;
203 if(l->tx<-6) l->txa+=0.004;
204 if(l->ty<-6) l->tya+=0.004;
205 if(l->txa>0.05 || l->txa<-0.05) l->txa/=1.7;
206 if(l->tya>0.05 || l->tya<-0.05) l->tya/=1.7;
209 /*Groovy, colour-shifting functions!*/
216 /* Calls itself <lensnum> times - with results from each lens/function. *
217 * After <length> calls to itself, it stops iterating and draws a point. */
218 static void iterate(float x, float y, long curcol, int length)
224 /*iterate(lenses[0].stepx(x,y),lenses[0].stepy(x,y),length-1);
225 iterate(lenses[1].stepx(x,y),lenses[1].stepy(x,y),length-1);
226 iterate(lenses[2].stepx(x,y),lenses[2].stepy(x,y),length-1);*/
227 for(i=0;i<lensnum;i++) {
229 case 0 : iterate(stepx( x, y, lenses[i]), stepy( x, y, lenses[i]), blend( curcol,colours[(int)lenses[i]->co].pixel ), length-1); break;
230 case 1 : iterate(stepx( x, y, lenses[i]), stepy( x, y, lenses[i]), colours[(int)lenses[i]->co].pixel, length-1); break;
231 case 2 : iterate(stepx( x, y, lenses[i]), stepy( x, y, lenses[i]), curcol, length-1); break;
239 /* Come on and iterate, iterate, iterate and sing... *
240 * Yeah, this function just calls iterate, mutate, *
241 * and then draws everything. */
242 static void step(void)
248 iterate(0,0,colours[wcol].pixel,length);
250 iterate(0,0,0xFFFFFF,length);
256 for(i=0;i<lensnum;i++) {
262 static void init_ifs(void)
266 XWindowAttributes xgwa;
268 delay = get_integer_resource("delay", "Delay");
269 length = get_integer_resource("length", "Detail");
270 mode = get_integer_resource("mode", "Mode");
272 norotate = get_boolean_resource("norotate", "NoRotate");
273 noscale = get_boolean_resource("noscale", "NoScale");
274 notranslate = get_boolean_resource("notranslate", "NoTranslate");
276 lensnum = get_integer_resource("lensnum", "Functions");
278 lenses = malloc(sizeof(Lens)*lensnum);
280 for(i=0;i<lensnum;i++) {
281 lenses[i]=malloc(sizeof(Lens));
284 /*Thanks go to Dad for teaching me how to allocate memory for struct**s . */
286 XGetWindowAttributes (dpy, w, &xgwa);
290 /*Initialise all this X shizzle*/
291 blackColor = BlackPixel(dpy, DefaultScreen(dpy));
292 whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
293 rw = RootWindow(dpy, screen_num);
294 screen_num = DefaultScreen(dpy);
295 gc = XCreateGC(dpy, rw, 0, NULL);
297 /* Do me some colourmap magic. If we're using blend mode, this is just *
298 * for the nice colours - we're still using true/hicolour. Screw me if *
299 * I'm going to work out how to blend with colourmaps - I'm too young to *
300 * die!! On a sidenote, this is mostly stolen from halftone because I *
301 * don't really know what the hell I'm doing, here. */
302 ncolours = get_integer_resource("colors", "Colors");
303 if(ncolours < lensnum) ncolours=lensnum; /*apparently you're allowed to do this kind of thing...*/
304 colours = (XColor *)calloc(ncolours, sizeof(XColor));
305 make_smooth_colormap ( dpy,
311 /*No, I didn't have a clue what that really did... hopefully I have some colours in an array, now.*/
312 wcol = (int)myrandom(ncolours);
314 /*Double buffering - I can't be bothered working out the XDBE thingy*/
315 backbuffer = XCreatePixmap(dpy, w, width, height, XDefaultDepth(dpy, screen_num));
324 /*Colourmapped colours for the general prettiness*/
325 for(i=0;i<lensnum;i++) {
326 CreateLens( myrandom(1)-0.5,
336 screenhack (Display *display, Window window)
345 screenhack_handle_events(dpy);
346 if (delay) usleep(delay);