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 :).
34 #include "screenhack.h"
35 #include <X11/Xutil.h>
39 char *progclass = "ShadeBobs";
46 "*ncolors: 64", /* changing this doesn't work particularly well */
51 XrmOptionDescRec options [] = {
52 { "-degrees", ".degrees", XrmoptionSepArg, 0 },
53 { "-color", ".color", XrmoptionSepArg, 0 },
54 { "-count", ".count", XrmoptionSepArg, 0 },
55 { "-delay", ".delay", XrmoptionSepArg, 0 },
56 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
60 static unsigned short nDegreeCount;
61 static double *anSinTable;
62 static unsigned short nMaxExtentX, nMaxExtentY;
63 static unsigned short nMinExtentX, nMinExtentY;
64 static unsigned short nHalfWidth, nHalfHeight;
67 #define RANDOM() ((int) (random() & 0X7FFFFFFFL))
70 /* Ahem. Chocolate is a flavor; not a food. Thank you */
77 char anDeltaMap[ MAPSIZE * MAPSIZE ]; /* 32 x 32 Delta Map */
78 double nVelocityX, nVelocityY;
79 double nAngleX, nAngleY;
80 short nExtentX, nExtentY;
84 static void ResetShadeBob( SShadeBob *pShadeBob )
86 pShadeBob->nAngleX = RANDOM() % nDegreeCount;
87 pShadeBob->nAngleY = RANDOM() % nDegreeCount;
89 pShadeBob->nExtentX = (RANDOM() % (nMaxExtentX - nMinExtentX)) + nMinExtentX;
90 pShadeBob->nExtentY = (RANDOM() % (nMaxExtentY - nMinExtentY)) + nMinExtentY;
94 static void InitShadeBob( SShadeBob *pShadeBob, Bool bDark )
99 for( iHeight=-16; iHeight<16; iHeight++ )
100 for( iWidth=-16; iWidth<16; iWidth++ )
102 nDelta = 9 - (sqrt( pow( iWidth+0.5, 2 ) + pow( iHeight+0.5, 2 ) ) / 2 );
103 if( nDelta < 0 ) nDelta = 0;
104 if( bDark ) nDelta = -nDelta;
105 pShadeBob->anDeltaMap[ (iWidth+(MAPSIZE/2))*MAPSIZE
106 + iHeight+(MAPSIZE/2) ] = (char)nDelta;
109 ResetShadeBob( pShadeBob );
113 static void Execute( SShadeBob *pShadeBob, Display *pDisplay,
115 GC *pGC, XImage *pXImage,
116 int ncolors, XColor *aXColors )
120 unsigned int nXPos, nYPos;
121 unsigned int iWidth, iHeight;
123 pShadeBob->nVelocityX += ( ( RANDOM() % 200 ) - 100 ) / 1000.0F;
124 pShadeBob->nVelocityY += ( ( RANDOM() % 200 ) - 100 ) / 1000.0F;
126 if( pShadeBob->nVelocityX > 4 ) pShadeBob->nVelocityX = 4;
127 else if( pShadeBob->nVelocityX < 3 ) pShadeBob->nVelocityX = 3;
128 if( pShadeBob->nVelocityY > 4 ) pShadeBob->nVelocityY = 4;
129 else if( pShadeBob->nVelocityY < 3 ) pShadeBob->nVelocityY = 3;
131 pShadeBob->nAngleX += pShadeBob->nVelocityX;
132 pShadeBob->nAngleY += pShadeBob->nVelocityY;
134 if( pShadeBob->nAngleX >= nDegreeCount ) pShadeBob->nAngleX -= nDegreeCount;
135 else if( pShadeBob->nAngleX < 0 ) pShadeBob->nAngleX += nDegreeCount;
136 if( pShadeBob->nAngleY >= nDegreeCount ) pShadeBob->nAngleY -= nDegreeCount;
137 else if( pShadeBob->nAngleY < 0 ) pShadeBob->nAngleY += nDegreeCount;
139 pShadeBob->nExtentX += ( RANDOM() % 5 ) - 2;
140 if( pShadeBob->nExtentX > nMaxExtentX ) pShadeBob->nExtentX = nMaxExtentX;
141 if( pShadeBob->nExtentX < nMinExtentX ) pShadeBob->nExtentX = nMinExtentX;
142 pShadeBob->nExtentY += ( RANDOM() % 5 ) - 2;
143 if( pShadeBob->nExtentY > nMaxExtentY ) pShadeBob->nExtentY = nMaxExtentY;
144 if( pShadeBob->nExtentY < nMinExtentY ) pShadeBob->nExtentY = nMinExtentY;
146 /* Trig is your friend :) */
147 nXPos = (unsigned int)(( anSinTable[ (int)pShadeBob->nAngleX ] * pShadeBob->nExtentX )
149 nYPos = (unsigned int)(( anSinTable[ (int)pShadeBob->nAngleY ] * pShadeBob->nExtentY )
152 for( iHeight=0; iHeight < MAPSIZE; iHeight++ )
154 for( iWidth=0; iWidth < MAPSIZE; iWidth++ )
156 nColor = XGetPixel( pXImage, nXPos + iWidth, nYPos + iHeight );
158 /* FIXME: Here is a loop I'd love to take out. */
159 for( nIndex=0; nIndex < ncolors; nIndex++ )
160 if( aXColors[ nIndex ].pixel == nColor )
163 nIndex += pShadeBob->anDeltaMap[ iWidth * MAPSIZE + iHeight ];
164 if( nIndex >= ncolors ) nIndex = ncolors-1;
165 if( nIndex < 0 ) nIndex = 0;
167 XPutPixel( pXImage, nXPos + iWidth, nYPos + iHeight,
168 aXColors[ nIndex ].pixel );
171 /* Place graphics in window */
172 XPutImage( pDisplay, MainWindow, *pGC, pXImage,
173 nXPos, nYPos, nXPos, nYPos, MAPSIZE, MAPSIZE );
174 XSync (pDisplay, False);
178 static void CreateTables( unsigned int nDegrees )
181 unsigned int iDegree;
182 anSinTable = calloc( nDegrees, sizeof(double) );
184 for( iDegree=0; iDegree<nDegrees; iDegree++ )
186 nRadian = ( (double)(2*iDegree) / (double)nDegrees ) * M_PI;
187 anSinTable[ iDegree ] = sin( nRadian );
192 static void SetPalette(Display *pDisplay, Window Win, char *sColor,
193 int *ncolorsP, XColor *aXColors )
195 XWindowAttributes XWinAttrib;
201 XGetWindowAttributes( pDisplay, Win, &XWinAttrib );
202 CMap = XWinAttrib.colormap;
204 Color.red = ( RANDOM() % 3 ) * 0x7FFF; /* Either full, half or none. */
205 Color.green = ( RANDOM() % 3 ) * 0x7FFF;
206 Color.blue = ( RANDOM() % 3 ) * 0x7FFF;
208 /* If Color is black, grey, or white, then make SURE its a color */
209 if( Color.red == Color.green && Color.green == Color.blue )
210 { Color.red = 0xFFFF;
211 Color.green = ( RANDOM() % 3 ) * 0x7FFF;
214 if( strcasecmp( sColor, "random" ) &&
215 !XParseColor( pDisplay, CMap, sColor, &Color ) )
217 "%s: color %s not found in database. Choosing to random...\n",
220 rgb_to_hsv( Color.red, Color.green, Color.blue, &nHue, &nSat, &nVal );
222 printf( "RGB (%d, %d, %d) = HSV (%d, %g, %g)\n",
223 Color.red, Color.green, Color.blue, nHue, nSat, nVal );
227 free_colors (pDisplay, CMap, aXColors, *ncolorsP);
229 *ncolorsP = get_integer_resource ("ncolors", "Integer");
230 if (*ncolorsP <= 0) *ncolorsP = 64;
232 /* allocate two color ramps, black -> color -> white. */
236 make_color_ramp( pDisplay, CMap, 0, 0, 0, nHue, nSat, nVal,
238 False, True, False );
240 make_color_ramp( pDisplay, CMap, nHue, nSat, nVal, 0, 0, 1,
242 False, True, False );
248 static void Initialize( Display *pDisplay, Window Win,
249 GC *pGC, XImage **pXImage,
250 int *ncolorsP, XColor *aXColors )
253 XWindowAttributes XWinAttribs;
256 /* Create the Image for drawing */
257 XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
259 /* Find the preferred bits-per-pixel. */
262 XPixmapFormatValues *pfv = XListPixmapFormats (pDisplay, &pfvc);
263 for (i = 0; i < pfvc; i++)
264 if (pfv[i].depth == XWinAttribs.depth)
266 bpp = pfv[i].bits_per_pixel;
274 *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
276 *pXImage = XCreateImage(pDisplay, XWinAttribs.visual,
279 XWinAttribs.width, XWinAttribs.height,
280 BitmapPad(pDisplay), 0);
281 (*pXImage)->data = calloc((*pXImage)->bytes_per_line,
284 /* These are precalculations used in Execute(). */
285 nMaxExtentX = ( XWinAttribs.width / 2 ) - 20;
286 nMaxExtentY = ( XWinAttribs.height / 2 ) - 20;
287 nMinExtentX = nMaxExtentX / 3;
288 nMinExtentY = nMaxExtentY / 3;
289 nHalfWidth = ( XWinAttribs.width / 2 ) - 16;
290 nHalfHeight = ( XWinAttribs.height / 2 ) - 16;
292 /* Create the Sin and Cosine lookup tables. */
293 nDegreeCount = get_integer_resource( "degrees", "Integer" );
294 if( nDegreeCount < 90 ) nDegreeCount = 90;
295 if( nDegreeCount > 5400 ) nDegreeCount = 5400;
296 CreateTables( nDegreeCount );
298 /* Get the colors. */
299 sColor = get_string_resource( "color", "Color" );
301 SetPalette( pDisplay, Win, "random", ncolorsP, aXColors );
303 SetPalette( pDisplay, Win, sColor, ncolorsP, aXColors );
307 void screenhack(Display *pDisplay, Window Win )
311 XColor aXColors[ 256 ];
313 unsigned char nShadeBobCount, iShadeBob;
314 SShadeBob *aShadeBobs;
316 time_t nTime = time( NULL );
317 unsigned short iFrame = 0;
319 int delay, cycles, i;
321 nShadeBobCount = get_integer_resource( "count", "Integer" );
322 if( nShadeBobCount > 64 ) nShadeBobCount = 64;
323 if( nShadeBobCount < 1 ) nShadeBobCount = 1;
325 if( ( aShadeBobs = calloc( nShadeBobCount, sizeof(SShadeBob) ) ) == NULL )
327 fprintf( stderr, "Could not allocate %d ShadeBobs\n", nShadeBobCount );
331 printf( "Allocated %d ShadeBobs\n", nShadeBobCount );
334 Initialize( pDisplay, Win, &gc, &pImage, &ncolors, aXColors );
336 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
337 InitShadeBob( &aShadeBobs[ iShadeBob ], iShadeBob % 2 );
339 delay = get_integer_resource( "delay", "Integer" );
340 cycles = get_integer_resource( "cycles", "Integer" ) * (nDegreeCount / 3);
345 screenhack_handle_events( pDisplay );
350 XClearWindow (pDisplay, Win);
351 memset (pImage->data, 0, pImage->bytes_per_line * pImage->height);
352 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
353 ResetShadeBob( &aShadeBobs[ iShadeBob ] );
354 SetPalette( pDisplay, Win, sColor, &ncolors, aXColors );
357 for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
358 Execute( &aShadeBobs[ iShadeBob ], pDisplay, Win, &gc,
359 pImage, ncolors, aXColors );
361 if( delay && !(i % 4) )
366 if( nTime - time( NULL ) )
368 printf( "FPS: %d\n", iFrame );
369 nTime = time( NULL );
376 free( pImage->data );
377 XDestroyImage( pImage );
382 /* End of Module - "shadebobs.c" */