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 :).
37 #include "screenhack.h"
38 #include <X11/Xutil.h>
42 char *progclass = "ShadeBobs";
45 "*degrees: 0", /* default: Automatic degree calculation */
49 "*ncolors: 64", /* changing this doesn't work particularly well */
54 XrmOptionDescRec options [] = {
55 { "-degrees", ".degrees", XrmoptionSepArg, 0 },
56 { "-color", ".color", XrmoptionSepArg, 0 },
57 { "-count", ".count", XrmoptionSepArg, 0 },
58 { "-delay", ".delay", XrmoptionSepArg, 0 },
59 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
63 static unsigned short nDegreeCount;
64 static double *anSinTable;
65 static unsigned short nMaxExtentX, nMaxExtentY;
66 static unsigned short nMinExtentX, nMinExtentY;
67 static unsigned short nHalfWidth, nHalfHeight;
69 static unsigned char nBobRadius, nBobDiameter;
70 static float nExtentDelta;
72 #define RANDOM() ((int) (random() & 0X7FFFFFFFL))
75 /* Ahem. Chocolate is a flavor; not a food. Thank you */
81 double nVelocityX, nVelocityY;
82 double nAngleX, nAngleY;
83 float nExtentX, nExtentY;
87 static void ResetShadeBob( SShadeBob *pShadeBob )
89 pShadeBob->nAngleX = RANDOM() % nDegreeCount;
90 pShadeBob->nAngleY = RANDOM() % nDegreeCount;
92 pShadeBob->nExtentX = (RANDOM() % (nMaxExtentX - nMinExtentX)) + nMinExtentX;
93 pShadeBob->nExtentY = (RANDOM() % (nMaxExtentY - nMinExtentY)) + nMinExtentY;
97 static void InitShadeBob( SShadeBob *pShadeBob, Bool bDark )
100 char iWidth, iHeight;
102 if( ( pShadeBob->anDeltaMap = calloc( nBobDiameter * nBobDiameter, sizeof(char) ) ) == NULL )
104 fprintf( stderr, "Could not allocate Delta Map!\n" );
108 for( iHeight=-nBobRadius; iHeight<nBobRadius; iHeight++ )
109 for( iWidth=-nBobRadius; iWidth<nBobRadius; iWidth++ )
111 nDelta = 9 - ( ( sqrt( pow( iWidth+0.5, 2 ) + pow( iHeight+0.5, 2 ) ) / nBobRadius ) * 8 );
112 if( nDelta < 0 ) nDelta = 0;
113 if( bDark ) nDelta = -nDelta;
114 pShadeBob->anDeltaMap[ ( iWidth + nBobRadius ) * nBobDiameter
115 + iHeight + nBobRadius ] = (char)nDelta;
118 ResetShadeBob( pShadeBob );
122 static void Execute( SShadeBob *pShadeBob, Display *pDisplay,
124 GC *pGC, XImage *pXImage,
125 int ncolors, XColor *aXColors )
129 unsigned int nXPos, nYPos;
130 unsigned int iWidth, iHeight;
132 pShadeBob->nVelocityX += ( ( RANDOM() % 200 ) - 100 ) / 1000.0F;
133 pShadeBob->nVelocityY += ( ( RANDOM() % 200 ) - 100 ) / 1000.0F;
135 if( pShadeBob->nVelocityX > 4 ) pShadeBob->nVelocityX = 4;
136 else if( pShadeBob->nVelocityX < 3 ) pShadeBob->nVelocityX = 3;
137 if( pShadeBob->nVelocityY > 4 ) pShadeBob->nVelocityY = 4;
138 else if( pShadeBob->nVelocityY < 3 ) pShadeBob->nVelocityY = 3;
140 pShadeBob->nAngleX += pShadeBob->nVelocityX;
141 pShadeBob->nAngleY += pShadeBob->nVelocityY;
143 if( pShadeBob->nAngleX >= nDegreeCount ) pShadeBob->nAngleX -= nDegreeCount;
144 if( pShadeBob->nAngleY >= nDegreeCount ) pShadeBob->nAngleY -= nDegreeCount;
146 pShadeBob->nExtentX += ( ( ( RANDOM() % 5 ) - 2 ) / 2.0F ) * nExtentDelta;
147 if( pShadeBob->nExtentX > nMaxExtentX ) pShadeBob->nExtentX = nMaxExtentX;
148 if( pShadeBob->nExtentX < nMinExtentX ) pShadeBob->nExtentX = nMinExtentX;
149 pShadeBob->nExtentY += ( ( ( RANDOM() % 5 ) - 2 ) / 2.0F ) * nExtentDelta;
150 if( pShadeBob->nExtentY > nMaxExtentY ) pShadeBob->nExtentY = nMaxExtentY;
151 if( pShadeBob->nExtentY < nMinExtentY ) pShadeBob->nExtentY = nMinExtentY;
153 /* Trig is your friend :) */
154 nXPos = (unsigned int)(( anSinTable[ (int)pShadeBob->nAngleX ] * pShadeBob->nExtentX )
156 nYPos = (unsigned int)(( anSinTable[ (int)pShadeBob->nAngleY ] * pShadeBob->nExtentY )
159 for( iHeight=0; iHeight<nBobDiameter; iHeight++ )
161 for( iWidth=0; iWidth<nBobDiameter; iWidth++ )
163 nColor = XGetPixel( pXImage, nXPos + iWidth, nYPos + iHeight );
165 /* FIXME: Here is a loop I'd love to take out. */
166 for( nIndex=0; nIndex < ncolors; nIndex++ )
167 if( aXColors[ nIndex ].pixel == nColor )
170 nIndex += pShadeBob->anDeltaMap[ iWidth * nBobDiameter + iHeight ];
171 if( nIndex >= ncolors ) nIndex = ncolors-1;
172 if( nIndex < 0 ) nIndex = 0;
174 XPutPixel( pXImage, nXPos + iWidth, nYPos + iHeight,
175 aXColors[ nIndex ].pixel );
179 XPutImage( pDisplay, MainWindow, *pGC, pXImage,
180 nXPos, nYPos, nXPos, nYPos, nBobDiameter, nBobDiameter );
181 XSync (pDisplay, False);
185 static void CreateTables( unsigned int nDegrees )
188 unsigned int iDegree;
189 anSinTable = calloc( nDegrees, sizeof(double) );
191 for( iDegree=0; iDegree<nDegrees; iDegree++ )
193 nRadian = ( (double)(2*iDegree) / (double)nDegrees ) * M_PI;
194 anSinTable[ iDegree ] = sin( nRadian );
199 static void SetPalette(Display *pDisplay, Window Win, char *sColor,
200 int *ncolorsP, XColor *aXColors )
202 XWindowAttributes XWinAttrib;
208 XGetWindowAttributes( pDisplay, Win, &XWinAttrib );
209 CMap = XWinAttrib.colormap;
211 Color.red = ( RANDOM() % 3 ) * 0x7FFF; /* Either full, half or none. */
212 Color.green = ( RANDOM() % 3 ) * 0x7FFF;
213 Color.blue = ( RANDOM() % 3 ) * 0x7FFF;
215 /* If Color is black, grey, or white, then make SURE its a color */
216 if( Color.red == Color.green && Color.green == Color.blue )
217 { Color.red = 0xFFFF;
218 Color.green = ( RANDOM() % 3 ) * 0x7FFF;
221 if( strcasecmp( sColor, "random" ) &&
222 !XParseColor( pDisplay, CMap, sColor, &Color ) )
224 "%s: color %s not found in database. Choosing to random...\n",
227 rgb_to_hsv( Color.red, Color.green, Color.blue, &nHue, &nSat, &nVal );
229 printf( "RGB (%d, %d, %d) = HSV (%d, %g, %g)\n",
230 Color.red, Color.green, Color.blue, nHue, nSat, nVal );
234 free_colors (pDisplay, CMap, aXColors, *ncolorsP);
236 *ncolorsP = get_integer_resource ("ncolors", "Integer");
237 if (*ncolorsP <= 0) *ncolorsP = 64;
239 /* allocate two color ramps, black -> color -> white. */
243 make_color_ramp( pDisplay, CMap, 0, 0, 0, nHue, nSat, nVal,
245 False, True, False );
247 make_color_ramp( pDisplay, CMap, nHue, nSat, nVal, 0, 0, 1,
249 False, True, False );
253 XSetWindowBackground( pDisplay, Win, aXColors[ 0 ].pixel );
257 static void Initialize( Display *pDisplay, Window Win,
258 GC *pGC, XImage **pXImage,
259 int *ncolorsP, XColor *aXColors )
262 XWindowAttributes XWinAttribs;
265 /* Create the Image for drawing */
266 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
268 /* Find the preferred bits-per-pixel. */
271 XPixmapFormatValues *pfv = XListPixmapFormats (pDisplay, &pfvc);
272 for (i = 0; i < pfvc; i++)
273 if (pfv[i].depth == XWinAttribs.depth)
275 bpp = pfv[i].bits_per_pixel;
283 *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
285 *pXImage = XCreateImage(pDisplay, XWinAttribs.visual,
288 XWinAttribs.width, XWinAttribs.height,
289 BitmapPad(pDisplay), 0);
290 (*pXImage)->data = calloc((*pXImage)->bytes_per_line,
293 /* These are precalculations used in Execute(). */
294 nBobDiameter = XWinAttribs.width / 25;
295 nBobRadius = nBobDiameter / 2;
296 nExtentDelta = nBobRadius / 5.0F;
298 printf( "Bob Diameter = %d\n", nBobDiameter );
301 nHalfWidth = ( XWinAttribs.width / 2 ) - nBobRadius;
302 nHalfHeight = ( XWinAttribs.height / 2 ) - nBobRadius;
303 nMaxExtentX = nHalfWidth - nBobRadius;
304 nMaxExtentY = nHalfHeight - nBobRadius;
305 nMinExtentX = nMaxExtentX / 3;
306 nMinExtentY = nMaxExtentY / 3;
308 /* Create the Sin and Cosine lookup tables. */
309 nDegreeCount = get_integer_resource( "degrees", "Integer" );
310 if( nDegreeCount == 0 ) nDegreeCount = ( XWinAttribs.width / 6 ) + 400;
311 else if( nDegreeCount < 90 ) nDegreeCount = 90;
312 else if( nDegreeCount > 5400 ) nDegreeCount = 5400;
313 CreateTables( nDegreeCount );
315 printf( "Using a %d degree circle.\n", nDegreeCount );
318 /* Get the colors. */
319 sColor = get_string_resource( "color", "Color" );
321 SetPalette( pDisplay, Win, "random", ncolorsP, aXColors );
323 SetPalette( pDisplay, Win, sColor, ncolorsP, aXColors );
327 void screenhack(Display *pDisplay, Window Win )
331 XColor aXColors[ 256 ];
333 unsigned char nShadeBobCount, iShadeBob;
334 SShadeBob *aShadeBobs;
336 time_t nTime = time( NULL );
337 unsigned short iFrame = 0;
339 int delay, cycles, i;
341 nShadeBobCount = get_integer_resource( "count", "Integer" );
342 if( nShadeBobCount > 64 ) nShadeBobCount = 64;
343 if( nShadeBobCount < 1 ) nShadeBobCount = 1;
345 if( ( aShadeBobs = calloc( nShadeBobCount, sizeof(SShadeBob) ) ) == NULL )
347 fprintf( stderr, "Could not allocate %d ShadeBobs\n", nShadeBobCount );
351 printf( "Allocated %d ShadeBobs\n", nShadeBobCount );
354 Initialize( pDisplay, Win, &gc, &pImage, &ncolors, aXColors );
356 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
357 InitShadeBob( &aShadeBobs[ iShadeBob ], iShadeBob % 2 );
359 delay = get_integer_resource( "delay", "Integer" );
360 cycles = get_integer_resource( "cycles", "Integer" ) * nDegreeCount;
365 screenhack_handle_events( pDisplay );
370 XClearWindow( pDisplay, Win );
371 memset( pImage->data, 0, pImage->bytes_per_line * pImage->height );
372 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
373 ResetShadeBob( &aShadeBobs[ iShadeBob ] );
374 SetPalette( pDisplay, Win, sColor, &ncolors, aXColors );
377 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
378 Execute( &aShadeBobs[ iShadeBob ], pDisplay, Win, &gc,
379 pImage, ncolors, aXColors );
381 if( delay && !(i % 4) )
386 if( nTime - time( NULL ) )
388 printf( "FPS: %d\n", iFrame );
389 nTime = time( NULL );
396 free( pImage->data );
397 XDestroyImage( pImage );
398 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
399 free( aShadeBobs[ iShadeBob ].anDeltaMap );
404 /* End of Module - "shadebobs.c" */