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";
50 "*degrees: 0", /* default: Automatic degree calculation */
54 "*ncolors: 64", /* changing this doesn't work particularly well */
59 XrmOptionDescRec options [] = {
60 { "-degrees", ".degrees", XrmoptionSepArg, 0 },
61 { "-color", ".color", XrmoptionSepArg, 0 },
62 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
63 { "-count", ".count", XrmoptionSepArg, 0 },
64 { "-delay", ".delay", XrmoptionSepArg, 0 },
65 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
69 static unsigned short iDegreeCount;
70 static double *anSinTable, *anCosTable;
71 static unsigned short iWinWidth, iWinHeight;
72 static unsigned short iWinCenterX, iWinCenterY;
74 static unsigned char iBobRadius, iBobDiameter;
75 static unsigned char iVelocity;
77 #define RANDOM() ((int) (random() & 0X7FFFFFFFL))
80 /* Ahem. Chocolate is a flavor; not a food. Thank you */
85 signed char *anDeltaMap;
86 double nAngle, nAngleDelta, nAngleInc;
91 static void ResetShadeBob( SShadeBob *pShadeBob )
93 pShadeBob->nPosX = RANDOM() % iWinWidth;
94 pShadeBob->nPosY = RANDOM() % iWinHeight;
95 pShadeBob->nAngle = RANDOM() % iDegreeCount;
96 pShadeBob->nAngleDelta = ( RANDOM() % iDegreeCount ) - ( iDegreeCount / 2.0F );
97 pShadeBob->nAngleInc = pShadeBob->nAngleDelta / 50.0F;
98 if( pShadeBob->nAngleInc == 0.0F )
99 pShadeBob->nAngleInc = ( pShadeBob->nAngleDelta > 0.0F ) ? 0.0001F : -0.0001F;
103 static void InitShadeBob( SShadeBob *pShadeBob, Bool bDark )
108 if( ( pShadeBob->anDeltaMap = calloc( iBobDiameter * iBobDiameter, sizeof(char) ) ) == NULL )
110 fprintf( stderr, "%s: Could not allocate Delta Map!\n", progclass );
114 for( iHeight=-iBobRadius; iHeight<iBobRadius; iHeight++ )
115 for( iWidth=-iBobRadius; iWidth<iBobRadius; iWidth++ )
117 nDelta = 9 - ( ( sqrt( pow( iWidth+0.5, 2 ) + pow( iHeight+0.5, 2 ) ) / iBobRadius ) * 8 );
118 if( nDelta < 0 ) nDelta = 0;
119 if( bDark ) nDelta = -nDelta;
120 pShadeBob->anDeltaMap[ ( iWidth + iBobRadius ) * iBobDiameter + iHeight + iBobRadius ] = (char)nDelta;
123 ResetShadeBob( pShadeBob );
127 /* A delta is calculated, and the shadebob turns at an increment. When the delta
128 * falls to 0, a new delta and increment are calculated. */
129 static void MoveShadeBob( SShadeBob *pShadeBob )
131 pShadeBob->nAngle += pShadeBob->nAngleInc;
132 pShadeBob->nAngleDelta -= pShadeBob->nAngleInc;
134 if( pShadeBob->nAngle >= iDegreeCount ) pShadeBob->nAngle -= iDegreeCount;
135 else if( pShadeBob->nAngle < 0 ) pShadeBob->nAngle += iDegreeCount;
137 if( ( pShadeBob->nAngleInc>0.0F && pShadeBob->nAngleDelta<pShadeBob->nAngleInc ) ||
138 ( pShadeBob->nAngleInc<=0.0F && pShadeBob->nAngleDelta>pShadeBob->nAngleInc ) )
140 pShadeBob->nAngleDelta = ( RANDOM() % iDegreeCount ) - ( iDegreeCount / 2.0F );
141 pShadeBob->nAngleInc = pShadeBob->nAngleDelta / 50.0F;
142 if( pShadeBob->nAngleInc == 0.0F )
143 pShadeBob->nAngleInc = ( pShadeBob->nAngleDelta > 0.0F ) ? 0.0001F : -0.0001F;
146 pShadeBob->nPosX = ( anSinTable[ (int)pShadeBob->nAngle ] * iVelocity ) + pShadeBob->nPosX;
147 pShadeBob->nPosY = ( anCosTable[ (int)pShadeBob->nAngle ] * iVelocity ) + pShadeBob->nPosY;
149 /* This wraps it around the screen. */
150 if( pShadeBob->nPosX >= iWinWidth ) pShadeBob->nPosX -= iWinWidth;
151 else if( pShadeBob->nPosX < 0 ) pShadeBob->nPosX += iWinWidth;
153 if( pShadeBob->nPosY >= iWinHeight ) pShadeBob->nPosY -= iWinHeight;
154 else if( pShadeBob->nPosY < 0 ) pShadeBob->nPosY += iWinHeight;
158 static void Execute( SShadeBob *pShadeBob, Display *pDisplay,
160 GC *pGC, XImage *pImage,
161 signed short iColorCount, unsigned long *aiColorVals )
163 unsigned long iColor;
165 int iPixelX, iPixelY;
166 unsigned int iWidth, iHeight;
168 MoveShadeBob( pShadeBob );
170 for( iHeight=0; iHeight<iBobDiameter; iHeight++ )
172 iPixelY = pShadeBob->nPosY + iHeight;
173 if( iPixelY >= iWinHeight ) iPixelY -= iWinHeight;
175 for( iWidth=0; iWidth<iBobDiameter; iWidth++ )
177 iPixelX = pShadeBob->nPosX + iWidth;
178 if( iPixelX >= iWinWidth ) iPixelX -= iWinWidth;
180 iColor = XGetPixel( pImage, iPixelX, iPixelY );
182 /* FIXME: Here is a loop I'd love to take out. */
183 for( iColorVal=0; iColorVal<iColorCount; iColorVal++ )
184 if( aiColorVals[ iColorVal ] == iColor )
187 iColorVal += pShadeBob->anDeltaMap[ iWidth * iBobDiameter + iHeight ];
188 if( iColorVal >= iColorCount ) iColorVal = iColorCount - 1;
189 if( iColorVal < 0 ) iColorVal = 0;
191 XPutPixel( pImage, iPixelX, iPixelY, aiColorVals[ iColorVal ] );
195 /* FIXME: if it's next to the top or left sides of screen this will break. However, it's not noticable. */
196 XPutImage( pDisplay, MainWindow, *pGC, pImage,
197 pShadeBob->nPosX, pShadeBob->nPosY, pShadeBob->nPosX, pShadeBob->nPosY, iBobDiameter, iBobDiameter );
198 XSync( pDisplay, False );
202 static void CreateTables( unsigned int nDegrees )
205 unsigned int iDegree;
206 anSinTable = calloc( nDegrees, sizeof(double) );
207 anCosTable = calloc( nDegrees, sizeof(double) );
209 for( iDegree=0; iDegree<nDegrees; iDegree++ )
211 nRadian = ( (double)(2*iDegree) / (double)nDegrees ) * M_PI;
212 anSinTable[ iDegree ] = sin( nRadian );
213 anCosTable[ iDegree ] = cos( nRadian );
218 static unsigned long * SetPalette(Display *pDisplay, Window Win, char *sColor, signed short *piColorCount )
220 XWindowAttributes XWinAttribs;
221 XColor Color, *aColors;
222 unsigned long *aiColorVals;
226 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
228 Color.red = RANDOM() % 0xFFFF;
229 Color.green = RANDOM() % 0xFFFF;
230 Color.blue = RANDOM() % 0xFFFF;
232 if( strcasecmp( sColor, "random" ) && !XParseColor( pDisplay, XWinAttribs.colormap, sColor, &Color ) )
233 fprintf( stderr, "%s: color %s not found in database. Choosing to random...\n", progname, sColor );
236 printf( "%s: Base color (RGB): <%d, %d, %d>\n", progclass, Color.red, Color.green, Color.blue );
239 *piColorCount = get_integer_resource( "ncolors", "Integer" );
240 if( *piColorCount < 2 ) *piColorCount = 2;
241 if( *piColorCount > 255 ) *piColorCount = 255;
243 aColors = calloc( *piColorCount, sizeof(XColor) );
244 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
246 for( iColor=0; iColor<*piColorCount; iColor++ )
248 nHalfColors = *piColorCount / 2.0F;
249 /* Black -> Base Color */
250 if( iColor < (*piColorCount/2) )
252 aColors[ iColor ].red = ( Color.red / nHalfColors ) * iColor;
253 aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor;
254 aColors[ iColor ].blue = ( Color.blue / nHalfColors ) * iColor;
256 /* Base Color -> White */
259 aColors[ iColor ].red = ( ( ( 0xFFFF - Color.red ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.red;
260 aColors[ iColor ].green = ( ( ( 0xFFFF - Color.green ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.green;
261 aColors[ iColor ].blue = ( ( ( 0xFFFF - Color.blue ) / nHalfColors ) * ( iColor - nHalfColors ) ) + Color.blue;
264 if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
266 /* start all over with less colors */
267 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
271 aColors = calloc( *piColorCount, sizeof(XColor) );
272 aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
276 aiColorVals[ iColor ] = aColors[ iColor ].pixel;
281 XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
287 static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
290 XWindowAttributes XWinAttribs;
293 /* Create the Image for drawing */
294 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
296 /* Find the preferred bits-per-pixel. (jwz) */
299 XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
300 for( i=0; i<pfvc; i++ )
301 if( pfv[ i ].depth == XWinAttribs.depth )
303 iBitsPerPixel = pfv[ i ].bits_per_pixel;
311 *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
313 *ppImage = XCreateImage( pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
314 XWinAttribs.width, XWinAttribs.height, BitmapPad( pDisplay ), 0 );
315 (*ppImage)->data = calloc((*ppImage)->bytes_per_line, (*ppImage)->height);
317 iWinWidth = XWinAttribs.width;
318 iWinHeight = XWinAttribs.height;
320 /* These are precalculations used in Execute(). */
321 iBobDiameter = ( ( iWinWidth < iWinHeight ) ? iWinWidth : iWinHeight ) / 25;
322 iBobRadius = iBobDiameter / 2;
324 printf( "%s: Bob Diameter = %d\n", progclass, iBobDiameter );
327 iWinCenterX = ( XWinAttribs.width / 2 ) - iBobRadius;
328 iWinCenterY = ( XWinAttribs.height / 2 ) - iBobRadius;
330 iVelocity = ( ( iWinWidth < iWinHeight ) ? iWinWidth : iWinHeight ) / 150;
332 /* Create the Sin and Cosine lookup tables. */
333 iDegreeCount = get_integer_resource( "degrees", "Integer" );
334 if( iDegreeCount == 0 ) iDegreeCount = ( XWinAttribs.width / 6 ) + 400;
335 else if( iDegreeCount < 90 ) iDegreeCount = 90;
336 else if( iDegreeCount > 5400 ) iDegreeCount = 5400;
337 CreateTables( iDegreeCount );
339 printf( "%s: Using a %d degree circle.\n", progclass );
342 /* Get the base color. */
343 sColor = get_string_resource( "color", "Color" );
347 void screenhack(Display *pDisplay, Window Win )
350 signed short iColorCount = 0;
351 unsigned long *aiColorVals = NULL;
352 XImage *pImage = NULL;
353 unsigned char nShadeBobCount, iShadeBob;
354 SShadeBob *aShadeBobs;
356 time_t nTime = time( NULL );
357 unsigned short iFrame = 0;
359 int delay, cycles, i;
361 nShadeBobCount = get_integer_resource( "count", "Integer" );
362 if( nShadeBobCount > 64 ) nShadeBobCount = 64;
363 if( nShadeBobCount < 1 ) nShadeBobCount = 1;
365 if( ( aShadeBobs = calloc( nShadeBobCount, sizeof(SShadeBob) ) ) == NULL )
367 fprintf( stderr, "%s: Could not allocate %d ShadeBobs\n", progclass, nShadeBobCount );
371 printf( "%s: Allocated %d ShadeBobs\n", progclass, nShadeBobCount );
374 Initialize( pDisplay, Win, &gc, &pImage );
376 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
377 InitShadeBob( &aShadeBobs[ iShadeBob ], iShadeBob % 2 );
379 delay = get_integer_resource( "delay", "Integer" );
380 cycles = get_integer_resource( "cycles", "Integer" ) * iDegreeCount;
385 screenhack_handle_events( pDisplay );
389 XWindowAttributes XWinAttribs;
390 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
393 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
394 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
395 ResetShadeBob( &aShadeBobs[ iShadeBob ] );
396 XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColorCount, 0 );
398 aiColorVals = SetPalette( pDisplay, Win, sColor, &iColorCount );
399 XClearWindow( pDisplay, Win );
402 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
403 Execute( &aShadeBobs[ iShadeBob ], pDisplay, Win, &gc, pImage, iColorCount, aiColorVals );
405 if( delay && !(i % 4) )
410 if( nTime - time( NULL ) )
412 printf( "%s: %d FPS\n", progclass, iFrame );
413 nTime = time( NULL );
421 free( pImage->data );
422 XDestroyImage( pImage );
423 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
424 free( aShadeBobs[ iShadeBob ].anDeltaMap );
430 /* End of Module - "shadebobs.c" */