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

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