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"
40 return(((float)random()/RAND_MAX)*up);
47 static Bool notranslate, noscale, norotate;
50 static int width,height;
59 static Pixmap backbuffer;
60 static XColor *colours;
62 static int screen_num;
64 static int blackColor, whiteColor;
66 char *progclass = "IFS";
74 "*notranslate: False",
80 XrmOptionDescRec options [] = {
81 { "-detail", ".length", XrmoptionSepArg, 0 },
82 { "-delay", ".delay", XrmoptionSepArg, 0 },
83 { "-mode", ".mode", XrmoptionSepArg, 0 },
84 { "-colors", ".colors", XrmoptionSepArg, 0 },
85 { "-functions", ".lensnum", XrmoptionSepArg, 0 },
86 { "-notranslate", ".notranslate", XrmoptionNoArg, "True" },
87 { "-noscale", ".noscale", XrmoptionNoArg, "True" },
88 { "-norotate", ".norotate", XrmoptionNoArg, "True" },
92 /*Takes the average of two colours, with some nifty bit-shifting*/
94 blend(long c1, long c2)
96 long R1=(c1 & 0xFF0000) >> 16;
97 long R2=(c2 & 0xFF0000) >> 16;
98 long G1=(c1 & 0x00FF00) >> 8;
99 long G2=(c2 & 0x00FF00) >> 8;
100 long B1=(c1 & 0x0000FF);
101 long B2=(c2 & 0x0000FF);
103 return (((R1+R2)/2 << 16) | ((G1+G2)/2 << 8) | ((B1+B2)/2));
106 /*Draw a point on the backbuffer*/
108 sp(float x, float y, long c)
112 if(x<0 || x>=width || y<0 || y>=height) return;
113 XSetForeground(dpy, gc, c);
114 XDrawPoint(dpy, backbuffer, gc, (int)x, (int)y);
117 /*Copy backbuffer to front buffer and clear backbuffer*/
128 XSetForeground(dpy, gc, blackColor);
138 /*Rotation, Scale, Translation X & Y*/
140 /*Old Rotation, Rotation Target, Rotation Counter*/
142 /*Old Scale, Scale Target, Scale Counter*/
144 /*Scale change, Translation change*/
151 CreateLens( float nr,
158 newlens->sa=newlens->txa=newlens->tya=0;
159 if(!norotate) newlens->r=nr;
162 if(!noscale) newlens->s=ns;
173 newlens->rc=newlens->sc=1;
178 stepx(float x, float y, Lens *l)
180 return l->s*cos(l->r)*x+l->s*sin(l->r)*y+l->tx;
183 stepy(float x, float y, Lens *l)
185 return l->s*sin(l->r)*-x+l->s*cos(l->r)*y+l->ty;
195 l->rt = myrandom(4)-2;
197 factor = (sin((-M_PI / 2.0) + M_PI * l->rc) + 1.0) / 2.0;
198 l->r=l->ro + (l->rt - l->ro) * factor;
205 /*Reset counter, obtain new target value*/
208 l->st = myrandom(2)-1;
210 factor = (sin((-M_PI / 2.0) + M_PI * l->sc) + 1.0) / 2.0;
211 /* Take average of old target and new target, using factor to *
212 * weight. It's computed sinusoidally, resulting in smooth, *
213 * rhythmic transitions. */
214 l->s=l->so + (l->st - l->so) * factor;
218 l->txa+=myrandom(0.004)-0.002;
219 l->tya+=myrandom(0.004)-0.002;
222 if(l->tx>6) l->txa-=0.004;
223 if(l->ty>6) l->tya-=0.004;
224 if(l->tx<-6) l->txa+=0.004;
225 if(l->ty<-6) l->tya+=0.004;
226 if(l->txa>0.05 || l->txa<-0.05) l->txa/=1.7;
227 if(l->tya>0.05 || l->tya<-0.05) l->tya/=1.7;
230 /*Groovy, colour-shifting functions!*/
237 /* Calls itself <lensnum> times - with results from each lens/function. *
238 * After <length> calls to itself, it stops iterating and draws a point. */
240 iterate(float x, float y, long curcol, int length)
246 for(i=0;i<lensnum;i++) {
248 case 0 : iterate(stepx( x, y, lenses[i]), stepy( x, y, lenses[i]), blend( curcol,colours[(int)lenses[i]->co].pixel ), length-1); break;
249 case 1 : iterate(stepx( x, y, lenses[i]), stepy( x, y, lenses[i]), colours[(int)lenses[i]->co].pixel, length-1); break;
250 case 2 : iterate(stepx( x, y, lenses[i]), stepy( x, y, lenses[i]), curcol, length-1); break;
258 /* Come on and iterate, iterate, iterate and sing... *
259 * Yeah, this function just calls iterate, mutate, *
260 * and then draws everything. */
268 iterate(0,0,colours[wcol].pixel,length);
270 iterate(0,0,0xFFFFFF,length);
276 for(i=0;i<lensnum;i++) {
287 XWindowAttributes xgwa;
289 delay = get_integer_resource("delay", "Delay");
290 length = get_integer_resource("length", "Detail");
291 mode = get_integer_resource("mode", "Mode");
293 norotate = get_boolean_resource("norotate", "NoRotate");
294 noscale = get_boolean_resource("noscale", "NoScale");
295 notranslate = get_boolean_resource("notranslate", "NoTranslate");
297 lensnum = get_integer_resource("lensnum", "Functions");
299 lenses = malloc(sizeof(Lens)*lensnum);
301 for(i=0;i<lensnum;i++) {
302 lenses[i]=malloc(sizeof(Lens));
305 /*Thanks go to Dad for teaching me how to allocate memory for struct**s . */
307 XGetWindowAttributes (dpy, w, &xgwa);
311 /*Initialise all this X shizzle*/
312 blackColor = BlackPixel(dpy, DefaultScreen(dpy));
313 whiteColor = WhitePixel(dpy, DefaultScreen(dpy));
314 rw = RootWindow(dpy, screen_num);
315 screen_num = DefaultScreen(dpy);
316 gc = XCreateGC(dpy, rw, 0, NULL);
318 /* Do me some colourmap magic. If we're using blend mode, this is just *
319 * for the nice colours - we're still using true/hicolour. Screw me if *
320 * I'm going to work out how to blend with colourmaps - I'm too young to *
321 * die!! On a sidenote, this is mostly stolen from halftone because I *
322 * don't really know what the hell I'm doing, here. */
323 ncolours = get_integer_resource("colors", "Colors");
324 if(ncolours < lensnum) ncolours=lensnum; /*apparently you're allowed to do this kind of thing...*/
325 colours = (XColor *)calloc(ncolours, sizeof(XColor));
326 make_smooth_colormap ( dpy,
332 /*No, I didn't have a clue what that really did... hopefully I have some colours in an array, now.*/
333 wcol = (int)myrandom(ncolours);
335 /*Double buffering - I can't be bothered working out the XDBE thingy*/
336 backbuffer = XCreatePixmap(dpy, w, width, height, XDefaultDepth(dpy, screen_num));
345 /*Colourmapped colours for the general prettiness*/
346 for(i=0;i<lensnum;i++) {
347 CreateLens( myrandom(1)-0.5,
357 screenhack (Display *display, Window window)
366 screenhack_handle_events(dpy);
367 if (delay) usleep(delay);