source: trunk/third/xscreensaver/hacks/shadebobs.c @ 20148

Revision 20148, 13.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* shadebobs, Copyright (c) 1999 Shane Smit <blackend@inconnect.com>
2 *
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
9 * implied warranty.
10 *
11 * Module - "shadebobs.c"
12 *
13 * Description:
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
16 *  black.
17 *  This keeps the screen in color balance at a chosen color.
18 *
19 *  Its kinda like 'The Force'
20 *   There is a light side, a dark side, and it keeps the world in balance.
21 *
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
29 *                real-time.
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.
37 */
38
39#include <math.h>
40#include "screenhack.h"
41#include <X11/Xutil.h>
42
43/* #define VERBOSE */
44
45char *progclass = "ShadeBobs";
46
47char *defaults [] = {
48  ".background: black",
49  ".foreground: white",
50  "*degrees:  0",       /* default: Automatic degree calculation */
51  "*color:    random",
52  "*count:    4",
53  "*cycles:   10",
54  "*ncolors:  64",    /* changing this doesn't work particularly well */
55  "*delay:    5000",
56  0
57};
58
59XrmOptionDescRec 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 },
66  { 0, 0, 0, 0 }
67};
68
69static unsigned short iDegreeCount;
70static double *anSinTable, *anCosTable;
71static unsigned short iWinWidth, iWinHeight;
72static unsigned short iWinCenterX, iWinCenterY;
73static char *sColor;
74static unsigned char iBobRadius, iBobDiameter;
75static unsigned char iVelocity;
76
77#define RANDOM() ((int) (random() & 0X7FFFFFFFL))
78
79
80/* Ahem. Chocolate is a flavor; not a food. Thank you */
81
82
83typedef struct
84{
85        signed char *anDeltaMap;
86        double nAngle, nAngleDelta, nAngleInc;
87        double nPosX, nPosY;
88} SShadeBob;
89
90
91static void ResetShadeBob( SShadeBob *pShadeBob )
92{
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;
100}
101
102
103static void InitShadeBob( SShadeBob *pShadeBob, Bool bDark )
104{
105        double nDelta;
106        int iWidth, iHeight;
107
108        if( ( pShadeBob->anDeltaMap = calloc( iBobDiameter * iBobDiameter, sizeof(char) ) ) == NULL )
109        {
110                fprintf( stderr, "%s: Could not allocate Delta Map!\n", progclass );
111                return;
112        }
113
114        for( iHeight=-iBobRadius; iHeight<iBobRadius; iHeight++ )
115                for( iWidth=-iBobRadius; iWidth<iBobRadius; iWidth++ )
116                {
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;
121                }
122 
123        ResetShadeBob( pShadeBob );
124}
125
126
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. */
129static void MoveShadeBob( SShadeBob *pShadeBob )
130{
131        pShadeBob->nAngle          += pShadeBob->nAngleInc;
132        pShadeBob->nAngleDelta -= pShadeBob->nAngleInc;
133
134        if( pShadeBob->nAngle >= iDegreeCount ) pShadeBob->nAngle -= iDegreeCount;
135        else if( pShadeBob->nAngle < 0 )                pShadeBob->nAngle += iDegreeCount;
136       
137        if( ( pShadeBob->nAngleInc>0.0F  && pShadeBob->nAngleDelta<pShadeBob->nAngleInc ) ||
138            ( pShadeBob->nAngleInc<=0.0F && pShadeBob->nAngleDelta>pShadeBob->nAngleInc ) )
139        {
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;
144        }
145       
146        pShadeBob->nPosX = ( anSinTable[ (int)pShadeBob->nAngle ] * iVelocity ) + pShadeBob->nPosX;
147        pShadeBob->nPosY = ( anCosTable[ (int)pShadeBob->nAngle ] * iVelocity ) + pShadeBob->nPosY;
148
149        /* This wraps it around the screen. */
150        if( pShadeBob->nPosX >= iWinWidth )     pShadeBob->nPosX -= iWinWidth;
151        else if( pShadeBob->nPosX < 0 )         pShadeBob->nPosX += iWinWidth;
152       
153        if( pShadeBob->nPosY >= iWinHeight )    pShadeBob->nPosY -= iWinHeight;
154        else if( pShadeBob->nPosY < 0 )                 pShadeBob->nPosY += iWinHeight;
155}
156
157
158static void Execute( SShadeBob *pShadeBob, Display *pDisplay,
159                     Window MainWindow,
160                     GC *pGC, XImage *pImage,
161                     signed short iColorCount, unsigned long *aiColorVals )
162{
163        unsigned long iColor;
164        short iColorVal;
165        int iPixelX, iPixelY;
166        unsigned int iWidth, iHeight;
167
168        MoveShadeBob( pShadeBob );
169       
170        for( iHeight=0; iHeight<iBobDiameter; iHeight++ )
171        {
172                iPixelY = pShadeBob->nPosY + iHeight;
173                if( iPixelY >= iWinHeight )     iPixelY -= iWinHeight;
174
175                for( iWidth=0; iWidth<iBobDiameter; iWidth++ )
176                {
177                        iPixelX = pShadeBob->nPosX + iWidth;
178                        if( iPixelX >= iWinWidth )      iPixelX -= iWinWidth;
179
180                        iColor = XGetPixel( pImage, iPixelX, iPixelY );
181
182                        /*  FIXME: Here is a loop I'd love to take out. */
183                        for( iColorVal=0; iColorVal<iColorCount; iColorVal++ )
184                                if( aiColorVals[ iColorVal ] == iColor )
185                                        break;
186
187                        iColorVal += pShadeBob->anDeltaMap[ iWidth * iBobDiameter + iHeight ];
188                        if( iColorVal >= iColorCount ) iColorVal = iColorCount - 1;
189                        if( iColorVal < 0 )                        iColorVal = 0;
190
191                        XPutPixel( pImage, iPixelX, iPixelY, aiColorVals[ iColorVal ] );
192                }
193        }
194
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 );
199}
200
201
202static void CreateTables( unsigned int nDegrees )
203{
204        double nRadian;
205        unsigned int iDegree;
206        anSinTable = calloc( nDegrees, sizeof(double) );
207        anCosTable = calloc( nDegrees, sizeof(double) );
208
209        for( iDegree=0; iDegree<nDegrees; iDegree++ )
210        {
211                nRadian = ( (double)(2*iDegree) / (double)nDegrees ) * M_PI;
212                anSinTable[ iDegree ] = sin( nRadian );
213                anCosTable[ iDegree ] = cos( nRadian );
214        }
215}
216
217
218static unsigned long * SetPalette(Display *pDisplay, Window Win, char *sColor, signed short *piColorCount )
219{
220        XWindowAttributes XWinAttribs;
221        XColor Color, *aColors;
222        unsigned long *aiColorVals;
223        signed short iColor;
224        float nHalfColors;
225       
226        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
227       
228        Color.red =   RANDOM() % 0xFFFF;
229        Color.green = RANDOM() % 0xFFFF;
230        Color.blue =  RANDOM() % 0xFFFF;
231
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 );
234
235#ifdef VERBOSE
236        printf( "%s: Base color (RGB): <%d, %d, %d>\n", progclass, Color.red, Color.green, Color.blue );
237#endif  /*  VERBOSE */
238
239        *piColorCount = get_integer_resource( "ncolors", "Integer" );
240        if( *piColorCount <   2 )       *piColorCount = 2;
241        if( *piColorCount > 255 )       *piColorCount = 255;
242
243        aColors    = calloc( *piColorCount, sizeof(XColor) );
244        aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
245       
246        for( iColor=0; iColor<*piColorCount; iColor++ )
247        {
248                nHalfColors = *piColorCount / 2.0F;
249                /* Black -> Base Color */
250                if( iColor < (*piColorCount/2) )
251                {
252                        aColors[ iColor ].red   = ( Color.red   / nHalfColors ) * iColor;
253                        aColors[ iColor ].green = ( Color.green / nHalfColors ) * iColor;
254                        aColors[ iColor ].blue  = ( Color.blue  / nHalfColors ) * iColor;
255                }
256                /* Base Color -> White */
257                else
258                {
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;
262                }
263
264                if( !XAllocColor( pDisplay, XWinAttribs.colormap, &aColors[ iColor ] ) )
265                {
266                        /* start all over with less colors */   
267                        XFreeColors( pDisplay, XWinAttribs.colormap, aiColorVals, iColor, 0 );
268                        free( aColors );
269                        free( aiColorVals );
270                        piColorCount--;
271                        aColors     = calloc( *piColorCount, sizeof(XColor) );
272                        aiColorVals = calloc( *piColorCount, sizeof(unsigned long) );
273                        iColor = -1;
274                }
275                else
276                        aiColorVals[ iColor ] = aColors[ iColor ].pixel;
277        }
278
279        free( aColors );
280
281        XSetWindowBackground( pDisplay, Win, aiColorVals[ 0 ] );
282
283        return aiColorVals;
284}
285
286
287static void Initialize( Display *pDisplay, Window Win, GC *pGC, XImage **ppImage )
288{
289        XGCValues gcValues;
290        XWindowAttributes XWinAttribs;
291        int iBitsPerPixel;
292
293        /* Create the Image for drawing */
294        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
295
296        /* Find the preferred bits-per-pixel. (jwz) */
297        {
298                int i, pfvc = 0;
299                XPixmapFormatValues *pfv = XListPixmapFormats( pDisplay, &pfvc );
300                for( i=0; i<pfvc; i++ )
301                        if( pfv[ i ].depth == XWinAttribs.depth )
302                        {
303                                iBitsPerPixel = pfv[ i ].bits_per_pixel;
304                                break;
305                        }
306                if( pfv )
307                        XFree (pfv);
308        }
309
310        /*  Create the GC. */
311        *pGC = XCreateGC( pDisplay, Win, 0, &gcValues );
312
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);
316
317        iWinWidth = XWinAttribs.width;
318        iWinHeight = XWinAttribs.height;
319
320        /*  These are precalculations used in Execute(). */
321        iBobDiameter = ( ( iWinWidth < iWinHeight ) ? iWinWidth : iWinHeight ) / 25;
322        iBobRadius = iBobDiameter / 2;
323#ifdef VERBOSE
324        printf( "%s: Bob Diameter = %d\n", progclass, iBobDiameter );
325#endif
326
327        iWinCenterX = ( XWinAttribs.width / 2 ) - iBobRadius;
328        iWinCenterY = ( XWinAttribs.height / 2 ) - iBobRadius;
329
330        iVelocity = ( ( iWinWidth < iWinHeight ) ? iWinWidth : iWinHeight ) / 150;
331       
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 );
338#ifdef VERBOSE
339        printf( "%s: Using a %d degree circle.\n", progclass );
340#endif /* VERBOSE */
341 
342        /*  Get the base color. */
343        sColor = get_string_resource( "color", "Color" );
344}
345
346
347void screenhack(Display *pDisplay, Window Win )
348{
349        GC gc;
350        signed short iColorCount = 0;
351        unsigned long *aiColorVals = NULL;
352        XImage *pImage = NULL;
353        unsigned char nShadeBobCount, iShadeBob;
354        SShadeBob *aShadeBobs;
355#ifdef VERBOSE
356        time_t nTime = time( NULL );
357        unsigned short iFrame = 0;
358#endif  /*  VERBOSE */
359        int delay, cycles, i;
360
361        nShadeBobCount = get_integer_resource( "count", "Integer" );
362        if( nShadeBobCount > 64 ) nShadeBobCount = 64;
363        if( nShadeBobCount <  1 ) nShadeBobCount = 1;
364
365        if( ( aShadeBobs = calloc( nShadeBobCount, sizeof(SShadeBob) ) ) == NULL )
366        {
367                fprintf( stderr, "%s: Could not allocate %d ShadeBobs\n", progclass, nShadeBobCount );
368                return;
369        }
370#ifdef VERBOSE
371        printf( "%s: Allocated %d ShadeBobs\n", progclass, nShadeBobCount );
372#endif  /*  VERBOSE */
373
374        Initialize( pDisplay, Win, &gc, &pImage );
375
376        for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
377                InitShadeBob( &aShadeBobs[ iShadeBob ], iShadeBob % 2 );
378
379        delay = get_integer_resource( "delay", "Integer" );
380        cycles = get_integer_resource( "cycles", "Integer" ) * iDegreeCount;
381        i = cycles;
382
383        while( 1 )
384        {
385                screenhack_handle_events( pDisplay );
386
387                if( i++ >= cycles )
388                {
389                        XWindowAttributes XWinAttribs;
390                        XGetWindowAttributes( pDisplay, Win, &XWinAttribs );
391
392                        i = 0;
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 );
397                        free( aiColorVals );
398                        aiColorVals = SetPalette( pDisplay, Win, sColor, &iColorCount );
399                        XClearWindow( pDisplay, Win );
400                }
401
402                for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
403                        Execute( &aShadeBobs[ iShadeBob ], pDisplay, Win, &gc, pImage, iColorCount, aiColorVals );
404
405                if( delay && !(i % 4) )
406                        usleep(delay);
407
408#ifdef VERBOSE
409                iFrame++;
410                if( nTime - time( NULL ) )
411                {
412                        printf( "%s: %d FPS\n", progclass, iFrame );
413                        nTime = time( NULL );
414                        iFrame = 0;
415                }
416#endif  /*  VERBOSE */
417        }
418
419        free( anSinTable );
420        free( anCosTable );
421        free( pImage->data );
422        XDestroyImage( pImage );
423        for( iShadeBob=0; iShadeBob<nShadeBobCount; iShadeBob++ )
424                free( aShadeBobs[ iShadeBob ].anDeltaMap );
425        free( aShadeBobs );
426        free( aiColorVals );
427}
428
429
430/* End of Module - "shadebobs.c" */
431
432/* vim: ts=4
433 */
Note: See TracBrowser for help on using the repository browser.