1 /* Bumps, Copyright (c) 2002 Shane Smit <CodeWeaver@DigitalLoom.org>
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
15 * This is typical bump-mapping. The actual bump map is generated by a screen
16 * grab. The light source is represented by a spotlight of random color. This
17 * spotlight randomly traverses the bump map in a sinus pattern.
19 * Essentially, it 3D-izes your desktop, based on color intensity.
21 * Modification History:
22 * [10/01/99] - Shane Smit: Creation
23 * [10/08/99] - Shane Smit: Port to C. (Ick)
24 * [03/08/02] - Shane Smit: New movement code.
31 void CreateSpotLight( SSpotLight *pSpotLight, uint16_ iDiameter, uint16_ nColorCount )
34 int16_ iHeight, iWidth;
36 pSpotLight->nDiameter = iDiameter;
38 printf( "%s: Light Diameter: %d\n", progclass, pSpotLight->nDiameter );
41 pSpotLight->aLightMap = calloc( pSpotLight->nDiameter * pSpotLight->nDiameter, sizeof(uint8_) );
42 memset( pSpotLight->aLightMap, 0, pSpotLight->nDiameter * pSpotLight->nDiameter );
44 /* The falloff max values... 3/4 of the entire lightmap. */
45 pSpotLight->nRadius = (uint16_)(pSpotLight->nDiameter / 2.5F);
47 for( iHeight=-pSpotLight->nRadius; iHeight<pSpotLight->nRadius; iHeight++ )
48 for( iWidth=-pSpotLight->nRadius; iWidth<pSpotLight->nRadius; iWidth++ )
50 nDelta = ( nColorCount * 2.5F ) - ( ( sqrt( pow( iWidth+0.5F, 2 ) + pow( iHeight+0.5F, 2 ) ) / pSpotLight->nRadius ) * ( nColorCount * 2.5F ) );
51 nDelta += nColorCount;
52 if( nDelta >= ( nColorCount * 2 ) ) nDelta = ( nColorCount * 2 ) - 1;
53 if( nDelta >= nColorCount )
54 pSpotLight->aLightMap[ ( ( iHeight + (pSpotLight->nDiameter/2) ) * pSpotLight->nDiameter ) + iWidth + (pSpotLight->nDiameter/2) ] = (uint8_)nDelta;
57 /* The actual lightmap... Use 1/4 to save time within the loop. */
58 pSpotLight->nRadius = pSpotLight->nDiameter / 4;
60 for( iHeight=-pSpotLight->nRadius; iHeight<pSpotLight->nRadius; iHeight++ )
61 for( iWidth=-pSpotLight->nRadius; iWidth<pSpotLight->nRadius; iWidth++ )
63 nDelta = nColorCount - ( ( sqrt( pow( iWidth+0.5F, 2 ) + pow( iHeight+0.5F, 2 ) ) / pSpotLight->nRadius ) * ( nColorCount - 1 ) );
65 pSpotLight->aLightMap[ ( ( iHeight + (pSpotLight->nDiameter/2) ) * pSpotLight->nDiameter ) + iWidth + (pSpotLight->nDiameter/2) ] = (uint8_)nDelta;
68 pSpotLight->nRadius = pSpotLight->nDiameter / 2; /* Now set the radius back to what it should be. */
69 pSpotLight->nAccelX = 0;
70 pSpotLight->nAccelY = 0;
71 pSpotLight->nVelocityX = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax;
72 pSpotLight->nVelocityY = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax;
76 void CalcLightPos( SBumps *pBumps )
78 SSpotLight *pSpotLight = &pBumps->SpotLight;
82 if( pSpotLight->nXPos < pSpotLight->nDiameter * 1 ) nGravity = 1.0f;
83 else if( pSpotLight->nXPos > pBumps->iWinWidth - ( pSpotLight->nDiameter * 1 ) ) nGravity = -1.0f;
84 else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f;
86 pSpotLight->nAccelX += nGravity * ( pSpotLight->nAccelMax / 10.0f );
87 if( pSpotLight->nAccelX < -pSpotLight->nAccelMax ) pSpotLight->nAccelX = -pSpotLight->nAccelMax;
88 else if( pSpotLight->nAccelX > pSpotLight->nAccelMax ) pSpotLight->nAccelX = pSpotLight->nAccelMax;
90 pSpotLight->nVelocityX += pSpotLight->nAccelX;
91 if( pSpotLight->nVelocityX < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = -pSpotLight->nVelocityMax;
92 else if( pSpotLight->nVelocityX > pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = pSpotLight->nVelocityMax;
94 pSpotLight->nXPos += pSpotLight->nVelocityX;
97 if( pSpotLight->nYPos < pSpotLight->nDiameter * 1 ) nGravity = 1.0f;
98 else if( pSpotLight->nYPos > pBumps->iWinHeight - ( pSpotLight->nDiameter * 1 ) ) nGravity = -1.0f;
99 else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f;
101 pSpotLight->nAccelY += nGravity * ( pSpotLight->nAccelMax / 10.0f );
102 if( pSpotLight->nAccelY < -pSpotLight->nAccelMax ) pSpotLight->nAccelY = -pSpotLight->nAccelMax;
103 else if( pSpotLight->nAccelY > pSpotLight->nAccelMax ) pSpotLight->nAccelY = pSpotLight->nAccelMax;
105 pSpotLight->nVelocityY += pSpotLight->nAccelY;
106 if( pSpotLight->nVelocityY < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = -pSpotLight->nVelocityMax;
107 else if( pSpotLight->nVelocityY > pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = pSpotLight->nVelocityMax;
109 pSpotLight->nYPos += pSpotLight->nVelocityY;
113 void CreateBumps( SBumps *pBumps, Display *pNewDisplay, Window NewWin )
115 XWindowAttributes XWinAttribs;
118 uint16_ iWidth, iHeight;
121 XGetWindowAttributes( pNewDisplay, NewWin, &XWinAttribs );
122 pBumps->iWinWidth = XWinAttribs.width;
123 pBumps->iWinHeight = XWinAttribs.height;
124 pBumps->SpotLight.nXPos = XWinAttribs.width / 2.0f;
125 pBumps->SpotLight.nYPos = XWinAttribs.height / 2.0f;
126 pBumps->SpotLight.nVelocityMax = ( ( XWinAttribs.width < XWinAttribs.height ) ? XWinAttribs.width : XWinAttribs.height ) / 128.0f;
127 pBumps->SpotLight.nAccelMax = pBumps->SpotLight.nVelocityMax / 10.0f;
128 pBumps->pDisplay = pNewDisplay;
129 pBumps->Win = NewWin;
131 pBumps->pXImage = XCreateImage( pBumps->pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
132 pBumps->iWinWidth, pBumps->iWinHeight, BitmapPad( pBumps->pDisplay ), 0 );
133 pBumps->pXImage->data = calloc( pBumps->pXImage->bytes_per_line * pBumps->pXImage->height, sizeof(int8_) );
135 GCValues.function = GXcopy;
136 GCValues.subwindow_mode = IncludeInferiors;
137 nGCFlags = GCForeground | GCFunction;
138 if( use_subwindow_mode_p( XWinAttribs.screen, pBumps->Win ) ) /* See grabscreen.c */
139 nGCFlags |= GCSubwindowMode;
140 pBumps->GraphicsContext = XCreateGC( pBumps->pDisplay, pBumps->Win, nGCFlags, &GCValues );
142 SetPalette( pBumps, &XWinAttribs );
143 iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 3;
144 CreateSpotLight( &pBumps->SpotLight, iDiameter, pBumps->nColorCount );
145 InitBumpMap( pBumps, &XWinAttribs );
147 /* Clear the image. */
148 if (pBumps->aXColors[ 0 ].pixel == 0)
149 memset (pBumps->pXImage->data, 0,
150 pBumps->pXImage->bytes_per_line * pBumps->pXImage->height);
152 for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
153 for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
154 XPutPixel( pBumps->pXImage, iWidth, iHeight,
155 pBumps->aXColors[ 0 ].pixel );
156 XSetWindowBackground( pBumps->pDisplay, pBumps->Win,
157 pBumps->aXColors[ 0 ].pixel );
158 XClearWindow (pBumps->pDisplay, pBumps->Win);
162 void SetPalette( SBumps *pBumps, XWindowAttributes *pXWinAttribs )
165 char *sColor; /* Spotlight Color */
169 sColor = get_string_resource( "color", "Color" );
171 Color.red = RANDOM() % 0xFFFF;
172 Color.green = RANDOM() % 0xFFFF;
173 Color.blue = RANDOM() % 0xFFFF;
175 /* Make one color full intesity to avoid dark spotlights. */
176 switch( RANDOM() % 3 )
178 case 0: Color.red = 0xFFFF; break;
179 case 1: Color.green = 0xFFFF; break;
180 case 2: Color.blue = 0xFFFF; break;
183 if( strcasecmp( sColor, "random" ) && !XParseColor( pBumps->pDisplay, pXWinAttribs->colormap, sColor, &Color ) )
184 fprintf( stderr, "%s: color %s not found in database. Choosing random...\n", progname, sColor );
187 printf( "%s: Spotlight color is <%d,%d,%d> RGB.\n", progclass, Color.red, Color.green, Color.blue );
190 pBumps->nColorCount = get_integer_resource( "colorcount", "Integer" );
191 if( pBumps->nColorCount < 2 ) pBumps->nColorCount = 2;
192 if( pBumps->nColorCount > 128 ) pBumps->nColorCount = 128;
194 pBumps->aXColors = calloc( pBumps->nColorCount, sizeof(XColor ) );
195 aPixels = calloc( pBumps->nColorCount, sizeof(uint32_) );
197 /* Creates a phong shade: / SpotColor \ Index/ColorCount
198 * PhongShade = | ------------ | Index + ( 65535 - SpotColor )^
200 pBumps->nColorCount--;
201 for( iColor=0; iColor<=pBumps->nColorCount; iColor++ )
203 pBumps->aXColors[ iColor ].red = (uint16_)( ( ( Color.red / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - Color.red, iColor/(double)pBumps->nColorCount ) );
204 pBumps->aXColors[ iColor ].green = (uint16_)( ( ( Color.green / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - Color.green, iColor/(double)pBumps->nColorCount ) );
205 pBumps->aXColors[ iColor ].blue = (uint16_)( ( ( Color.blue / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - Color.blue, iColor/(double)pBumps->nColorCount ) );
207 if( !XAllocColor( pBumps->pDisplay, pXWinAttribs->colormap, &pBumps->aXColors[ iColor ] ) )
209 XFreeColors( pBumps->pDisplay, pXWinAttribs->colormap, aPixels, iColor, 0 );
210 free( pBumps->aXColors );
212 pBumps->nColorCount--;
213 pBumps->aXColors = calloc( pBumps->nColorCount, sizeof(XColor) );
214 aPixels = calloc( pBumps->nColorCount, sizeof(uint32_) );
218 aPixels[ iColor ] = pBumps->aXColors[ iColor ].pixel;
220 pBumps->nColorCount++;
223 printf( "%s: Allocated %d colors.\n", progclass, pBumps->nColorCount );
226 XSetWindowBackground( pBumps->pDisplay, pBumps->Win, pBumps->aXColors[ 0 ].pixel );
230 void InitBumpMap( SBumps *pBumps, XWindowAttributes *pXWinAttribs )
232 XImage *pScreenImage;
235 uint16_ iWidth, iHeight;
236 BOOL bInvert = (BOOL)get_boolean_resource( "invert", "Boolean" );
238 aColors = (XColor*)calloc( pBumps->iWinWidth, sizeof(XColor) );
239 grab_screen_image( pXWinAttribs->screen, pBumps->Win );
240 pScreenImage = XGetImage( pBumps->pDisplay, pBumps->Win, 0, 0, pBumps->iWinWidth, pBumps->iWinHeight, ~0L, ZPixmap );
242 /* jwz: get the grabbed bits off the screen fast */
243 XClearWindow (pBumps->pDisplay, pBumps->Win);
244 XSync (pBumps->pDisplay, 0);
246 pBumps->aBumpMap = calloc( pBumps->iWinWidth * pBumps->iWinHeight, sizeof(uint16_) );
247 for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
249 for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
250 aColors[ iWidth ].pixel = XGetPixel( pScreenImage, iWidth, iHeight );
252 XQueryColors( pBumps->pDisplay, pXWinAttribs->colormap, aColors, pBumps->iWinWidth );
255 for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
256 pBumps->aBumpMap[ ( iHeight * pBumps->iWinWidth ) + iWidth ] = (uint16_)
257 ( ( aColors[ iWidth ].red + aColors[ iWidth ].green + aColors[ iWidth ].blue ) / ( 0x2FFFD / (double)pBumps->SpotLight.nDiameter ) );
259 for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
260 pBumps->aBumpMap[ ( iHeight * pBumps->iWinWidth ) + iWidth ] = (uint16_)
261 ( pBumps->SpotLight.nDiameter - ( ( aColors[ iWidth ].red + aColors[ iWidth ].green + aColors[ iWidth ].blue ) / ( 0x2FFFD / (double)pBumps->SpotLight.nDiameter ) ) );
264 XDestroyImage( pScreenImage );
266 nSoften = get_integer_resource( "soften", "Integer" );
268 if( nSoften ) printf( "%s: Softening Bump Map %d time(s)...\n", progclass, nSoften );
271 SoftenBumpMap( pBumps );
276 void SoftenBumpMap( SBumps *pBumps )
280 uint16_ iWidth, iHeight;
281 uint16_ *pTempBuffer = calloc( pBumps->iWinWidth * pBumps->iWinHeight, sizeof(uint16_) );
283 for( iHeight=1; iHeight<pBumps->iWinHeight-1; iHeight++ )
285 pOffset = pBumps->aBumpMap + ( iHeight * pBumps->iWinWidth );
286 for( iWidth=1; iWidth<pBumps->iWinWidth-1; iWidth++ )
289 nHeight += pOffset[ iWidth ];
290 nHeight += pOffset[ iWidth - pBumps->iWinWidth ];
291 nHeight += pOffset[ iWidth + 1 ];
292 nHeight += pOffset[ iWidth + pBumps->iWinWidth ];
293 nHeight += pOffset[ iWidth - 1 ];
295 pTempBuffer[ ( iHeight * pBumps->iWinWidth ) + iWidth ] = nHeight;
299 memcpy( pBumps->aBumpMap, pTempBuffer, pBumps->iWinWidth * pBumps->iWinHeight * 2 );
304 void Execute( SBumps *pBumps )
306 uint16_ nLightXPos, nLightYPos;
307 uint16_ iWidth, iHeight;
308 uint16_ iLightWidth, iLightHeight;
313 CalcLightPos( pBumps );
315 /* Offset to upper left hand corner. */
316 nLightXPos = pBumps->SpotLight.nXPos - pBumps->SpotLight.nRadius;
317 nLightYPos = pBumps->SpotLight.nYPos - pBumps->SpotLight.nRadius;
319 for( iHeight=nLightYPos, iLightHeight=0; iLightHeight<pBumps->SpotLight.nDiameter; iHeight++, iLightHeight++ )
321 pBOffset = pBumps->aBumpMap + ( iHeight * pBumps->iWinWidth );
322 pLOffset = pBumps->SpotLight.aLightMap + ( iLightHeight * pBumps->SpotLight.nDiameter );
323 for( iWidth=nLightXPos, iLightWidth=0; iLightWidth<pBumps->SpotLight.nDiameter; iWidth++, iLightWidth++ )
325 if( pLOffset[ iLightWidth ] )
327 nX = pBOffset[ iWidth + 1 ] - pBOffset[ iWidth ] + iLightWidth;
328 nY = pBOffset[ iWidth + pBumps->iWinWidth ] - pBOffset[ iWidth ] + iLightHeight;
331 else if( nX >= pBumps->SpotLight.nDiameter ) nX = pBumps->SpotLight.nDiameter - 1;
334 else if( nY >= pBumps->SpotLight.nDiameter ) nY = pBumps->SpotLight.nDiameter - 1;
336 nColor = pBumps->SpotLight.aLightMap[ ( nY * pBumps->SpotLight.nDiameter ) + nX ];
337 if( nColor >= pBumps->nColorCount )
340 if( pLOffset[ iLightWidth ] >= pBumps->nColorCount )
341 if( nColor > pLOffset[ iLightWidth ] - pBumps->nColorCount )
342 nColor = pLOffset[ iLightWidth ] - pBumps->nColorCount;
344 XPutPixel( pBumps->pXImage, iWidth, iHeight, pBumps->aXColors[ nColor ].pixel );
347 XPutPixel( pBumps->pXImage, iWidth, iHeight, pBumps->aXColors[ 0 ].pixel );
351 XPutImage( pBumps->pDisplay, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, nLightXPos, nLightYPos, nLightXPos, nLightYPos, pBumps->SpotLight.nDiameter, pBumps->SpotLight.nDiameter );
352 XSync( pBumps->pDisplay, False );
356 void DestroyBumps( SBumps *pBumps )
358 DestroySpotLight( &pBumps->SpotLight );
359 free( pBumps->aXColors );
360 free( pBumps->aBumpMap );
361 XDestroyImage( pBumps->pXImage );
365 /* All messages to the screensaver are processed here. */
366 void screenhack( Display *pDisplay, Window Win )
371 time_t Time = time( NULL );
375 CreateBumps( &Bumps, pDisplay, Win );
376 iDelay = get_integer_resource( "delay", "Integer" );
380 screenhack_handle_events( pDisplay );
386 if( Time - time( NULL ) )
388 printf( "FPS: %d\n", iFrame );
395 DestroyBumps( &Bumps );