1 /* shadebobs, Copyright (c) 1999 Shane Smit <blackend@inconnect.com>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Module - "shadebobs.c"
14 * There are two little shading circles (bobs) that zip around the screen.
15 * one of them shades up towards white, and the other shades down toward
17 * This keeps the screen in color balance at a chosen color.
19 * Its kinda like 'The Force'
20 * There is a light side, a dark side, and it keeps the world in balance.
22 * [05/23/99] - Shane Smit: Creation
23 * [05/26/99] - Shane Smit: Port to C/screenhack for use with XScreenSaver
24 * [06/11/99] - Shane Smit: Stopped trying to rape the palette.
25 * [06/20/99] - jwz: cleaned up ximage handling, gave resoources short names,
26 * introduced delay, made it restart after N iterations.
27 * [06/21/99] - Shane Smit: Modified default values slightly, color changes
28 * on cycle, and the extents of the sinus pattern change in
30 * [06/22/99] - Shane Smit: Fixed delay to be fast and use little CPU :).
31 * [09/17/99] - Shane Smit: Made all calculations based on the size of the
32 * window. Thus, it'll look the same at 100x100 as it does at
33 * 1600x1200 ( Only smaller :).
34 * [04/24/00] - Shane Smit: Revamped entire source code:
35 * Shade Bob movement is calculated very differently.
36 * Base color can be any color now.
40 #include "screenhack.h"
41 #include <X11/Xutil.h>
45 char *progclass = "ShadeBobs";
48 "*degrees: 0", /* default: Automatic degree calculation */
52 "*ncolors: 64", /* changing this doesn't work particularly well */
57 XrmOptionDescRec options [] = {
58 { "-degrees", ".degrees", XrmoptionSepArg, 0 },
59 { "-color", ".color", XrmoptionSepArg, 0 },
60 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
61 { "-count", ".count", XrmoptionSepArg, 0 },
62 { "-delay", ".delay", XrmoptionSepArg, 0 },
63 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
67 static unsigned short iDegreeCount;
68 static double *anSinTable, *anCosTable;
69 static unsigned short iWinWidth, iWinHeight;
70 static unsigned short iWinCenterX, iWinCenterY;
72 static unsigned char iBobRadius, iBobDiameter;
73 static unsigned char iVelocity;
75 #define RANDOM() ((int) (random() & 0X7FFFFFFFL))
78 /* Ahem. Chocolate is a flavor; not a food. Thank you */
83 signed char *anDeltaMap;
84 double nAngle, nAngleDelta, nAngleInc;
89 static void ResetShadeBob( SShadeBob *pShadeBob )
91 pShadeBob->nPosX = RANDOM() % iWinWidth;
92 pShadeBob->nPosY = RANDOM() % iWinHeight;
93 pShadeBob->nAngle = RANDOM() % iDegreeCount;
94 pShadeBob->nAngleDelta = ( RANDOM() % iDegreeCount ) - ( iDegreeCount / 2.0F );
95 pShadeBob->nAngleInc = pShadeBob->nAngleDelta / 50.0F;
96 if( pShadeBob->nAngleInc == 0.0F )
97 pShadeBob->nAngleInc = ( pShadeBob->nAngleDelta > 0.0F ) ? 0.0001F : -0.0001F;
101 static void InitShadeBob( SShadeBob *pShadeBob, Bool bDark )
106 if( ( pShadeBob->anDeltaMap = calloc( iBobDiameter * iBobDiameter, sizeof(char) ) ) == NULL )
108 fprintf( stderr, "%s: Could not allocate Delta Map!\n", progclass );
112 for( iHeight=-iBobRadius; iHeight<iBobRadius; iHeight++ )
113 for( iWidth=-iBobRadius; iWidth<iBobRadius; iWidth++ )
115 nDelta = 9 - ( ( sqrt( pow( iWidth+0.5, 2 ) + pow( iHeight+0.5, 2 ) ) / iBobRadius ) * 8 );
116 if( nDelta < 0 ) nDelta = 0;
117 if( bDark ) nDelta = -nDelta;
118 pShadeBob->anDeltaMap[ ( iWidth + iBobRadius ) * iBobDiameter + iHeight + iBobRadius ] = (char)nDelta;
121 ResetShadeBob( pShadeBob );
125 /* A delta is calculated, and the shadebob turns at an increment. When the delta
126 * falls to 0, a new delta and increment are calculated. */
127 static void MoveShadeBob( SShadeBob *pShadeBob )
129 pShadeBob->nAngle += pShadeBob->nAngleInc;
130 pShadeBob->nAngleDelta -= pShadeBob->nAngleInc;
132 if( pShadeBob->nAngle >= iDegreeCount ) pShadeBob->nAngle -= iDegreeCount;
133 else if( pShadeBob->nAngle < 0 ) pShadeBob->nAngle += iDegreeCount;
135 if( ( pShadeBob->nAngleInc>0.0F && pShadeBob->nAngleDelta<pShadeBob->nAngleInc ) ||
136 ( pShadeBob->nAngleInc<=0.0F && pShadeBob->nAngleDelta>pShadeBob->nAngleInc ) )
138 pShadeBob->nAngleDelta = ( RANDOM() % iDegreeCount ) - ( iDegreeCount / 2.0F );
139 pShadeBob->nAngleInc = pShadeBob->nAngleDelta / 50.0F;
140 if( pShadeBob->nAngleInc == 0.0F )
141 pShadeBob->nAngleInc = ( pShadeBob->nAngleDelta > 0.0F ) ? 0.0001F : -0.0001F;
144 pShadeBob->nPosX = ( anSinTable[ (int)pShadeBob->nAngle ] * iVelocity ) + pShadeBob->nPosX;
145 pShadeBob->nPosY = ( anCosTable[ (int)pShadeBob->nAngle ] * iVelocity ) + pShadeBob->nPosY;
147 /* This wraps it around the screen. */
148 if( pShadeBob->nPosX >= iWinWidth ) pShadeBob->nPosX -= iWinWidth;
149 else if( pShadeBob->nPosX < 0 ) pShadeBob->nPosX += iWinWidth;
151 if( pShadeBob->nPosY >= iWinHeight ) pShadeBob->nPosY -= iWinHeight;
152 else if( pShadeBob->nPosY < 0 ) pShadeBob->nPosY += iWinHeight;
156 static void Execute( SShadeBob *pShadeBob, Display *pDisplay,
158 GC *pGC, XImage *pImage,
159 signed short iColorCount, unsigned long *aiColorVals )
161 unsigned long iColor;
163 int iPixelX, iPixelY;
164 unsigned int iWidth, iHeight;
166 MoveShadeBob( pShadeBob );
168 for( iHeight=0; iHeight<iBobDiameter; iHeight++ )
170 iPixelY = pShadeBob->nPosY + iHeight;
171 if( iPixelY >= iWinHeight ) iPixelY -= iWinHeight;
173 for( iWidth=0; iWidth<iBobDiameter; iWidth++ )
175 iPixelX = pShadeBob->nPosX + iWidth;
176 if( iPixelX >= iWinWidth ) iPixelX -= iWinWidth;
178 iColor = XGetPixel( pImage, iPixelX, iPixelY );
180 /* FIXME: Here is a loop I'd love to take out. */
181 for( iColorVal=0; iColorVal<iColorCount; iColorVal++ )
182 if( aiColorVals[ iColorVal ] == iColor )
185 iColorVal += pShadeBob->anDeltaMap[ iWidth * iBobDiameter + iHeight ];
186 if( iColorVal >= iColorCount ) iColorVal = iColorCount - 1;
187 if( iColorVal < 0 ) iColorVal = 0;
189 XPutPixel( pImage, iPixelX, iPixelY, aiColorVals[ iColorVal ] );
193 /* FIXME: if it's next to the top or left sides of screen this will break. However, it's not noticable. */
194 XPutImage( pDisplay, MainWindow, *pGC, pImage,
195 pShadeBob->nPosX, pShadeBob->nPosY, pShadeBob->nPosX, pShadeBob->nPosY, iBobDiameter, iBobDiameter );
196 XSync( pDisplay, False );
200 static void CreateTables( unsigned int nDegrees )
203 unsigned int iDegree;
204 anSinTable = calloc( nDegrees, sizeof(double) );
205 anCosTable = calloc( nDegrees, sizeof(double) );
207 for( iDegree=0; iDegree<nDegrees; iDegree++ )
209 nRadian = ( (double)(2*iDegree) / (double)nDegrees ) * M_PI;
210 anSinTable[ iDegree ] = sin( nRadian );
211 anCosTable[ iDegree ] = cos( nRadian );
216 static unsigned long * SetPalette(Display *pDisplay, Window Win, char *sColor, signed short *piColorCount )
218 XWindowAttributes XWinAttribs;
219 XColor Color, *aColors;
220 unsigned long *aiColorVals;
224 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
226 Color.red = RANDOM() % 0xFFFF;
227 Color.green = RANDOM() % 0xFFFF;
228 Color.blue = RANDOM() % 0xFFFF;
230 if( strcasecmp( sColor, "random" ) && !XParseColor( pDisplay, XWinAttribs.colormap, sColor, &Color ) )
231 fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, sColor );
234 printf( "%s: Base color (RGB): <%d, %d, %d>\n", progclass, Color.red, Color.green, Color.blue );
237 *piColorCount = get_integer_resource( "ncolors", "Integer" );
238 if( *piColorCount < 2 ) *piColorCount = 2;
239 if( *piColorCount > 255 ) *piColorCount = 255;
241 aColors = calloc( *piColorCount, sizeof(XColor) );
242 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
244 for( iColor=0; iColor<*piColorCount; iColor++ )
246 nHalfColors = *piColorCount / 2.0F;
247 /* Black -> Base Color */
248 if( iColor < (*piColorCount/2) )
250 aColors[ iColor ].red = ( Color.red / nHalfColors ) * iColor;
251 aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor;
252 aColors[ iColor ].blue = ( Color.blue / nHalfColors ) * iColor;
254 /* Base Color -> White */
257 aColors[ iColor ].red = ( ( ( 0xFFFF - Color.red ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.red;
258 aColors[ iColor ].green = ( ( ( 0xFFFF - Color.green ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.green;
259 aColors[ iColor ].blue = ( ( ( 0xFFFF - Color.blue ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.blue;
262 if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
264 /* start all over with less colors */
265 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
269 aColors = calloc( *piColorCount, sizeof(XColor) );
270 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
274 aiColorVals[ iColor ] = aColors[ iColor ].pixel;
279 XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
285 static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
288 XWindowAttributes XWinAttribs;
291 /* Create the Image for drawing */
292 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
294 /* Find the preferred bits-per-pixel. (jwz) */
297 XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
298 for( i=0; i<pfvc; i++ )
299 if( pfv[ i ].depth == XWinAttribs.depth )
301 iBitsPerPixel = pfv[ i ].bits_per_pixel;
309 *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
311 *ppImage = XCreateImage( pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
312 XWinAttribs.width, XWinAttribs.height, BitmapPad( pDisplay ), 0 );
313 (*ppImage)->data = calloc((*ppImage)->bytes_per_line, (*ppImage)->height);
315 iWinWidth = XWinAttribs.width;
316 iWinHeight = XWinAttribs.height;
318 /* These are precalculations used in Execute(). */
319 iBobDiameter = ( ( iWinWidth < iWinHeight ) ? iWinWidth : iWinHeight ) / 25;
320 iBobRadius = iBobDiameter / 2;
322 printf( "%s: Bob Diameter = %d\n", progclass, iBobDiameter );
325 iWinCenterX = ( XWinAttribs.width / 2 ) - iBobRadius;
326 iWinCenterY = ( XWinAttribs.height / 2 ) - iBobRadius;
328 iVelocity = ( ( iWinWidth < iWinHeight ) ? iWinWidth : iWinHeight ) / 150;
330 /* Create the Sin and Cosine lookup tables. */
331 iDegreeCount = get_integer_resource( "degrees", "Integer" );
332 if( iDegreeCount == 0 ) iDegreeCount = ( XWinAttribs.width / 6 ) + 400;
333 else if( iDegreeCount < 90 ) iDegreeCount = 90;
334 else if( iDegreeCount > 5400 ) iDegreeCount = 5400;
335 CreateTables( iDegreeCount );
337 printf( "%s: Using a %d degree circle.\n", progclass );
340 /* Get the base color. */
341 sColor = get_string_resource( "color", "Color" );
345 void screenhack(Display *pDisplay, Window Win )
348 signed short iColorCount = 0;
349 unsigned long *aiColorVals = NULL;
350 XImage *pImage = NULL;
351 unsigned char nShadeBobCount, iShadeBob;
352 SShadeBob *aShadeBobs;
354 time_t nTime = time( NULL );
355 unsigned short iFrame = 0;
357 int delay, cycles, i;
359 nShadeBobCount = get_integer_resource( "count", "Integer" );
360 if( nShadeBobCount > 64 ) nShadeBobCount = 64;
361 if( nShadeBobCount < 1 ) nShadeBobCount = 1;
363 if( ( aShadeBobs = calloc( nShadeBobCount, sizeof(SShadeBob) ) ) == NULL )
365 fprintf( stderr, "%s: Could not allocate %d ShadeBobs\n", progclass, nShadeBobCount );
369 printf( "%s: Allocated %d ShadeBobs\n", progclass, nShadeBobCount );
372 Initialize( pDisplay, Win, &gc, &pImage );
374 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
375 InitShadeBob( &aShadeBobs[ iShadeBob ], iShadeBob % 2 );
377 delay = get_integer_resource( "delay", "Integer" );
378 cycles = get_integer_resource( "cycles", "Integer" ) * iDegreeCount;
383 screenhack_handle_events( pDisplay );
387 XWindowAttributes XWinAttribs;
388 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
391 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
392 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
393 ResetShadeBob( &aShadeBobs[ iShadeBob ] );
394 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
396 aiColorVals = SetPalette( pDisplay, Win, sColor, &iColorCount );
397 XClearWindow( pDisplay, Win );
400 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
401 Execute( &aShadeBobs[ iShadeBob ], pDisplay, Win, &gc, pImage, iColorCount, aiColorVals );
403 if( delay && !(i % 4) )
408 if( nTime - time( NULL ) )
410 printf( "%s: %d FPS\n", progclass, iFrame );
411 nTime = time( NULL );
419 free( pImage->data );
420 XDestroyImage( pImage );
421 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
422 free( aShadeBobs[ iShadeBob ].anDeltaMap );
428 /* End of Module - "shadebobs.c" */