1 /* Bumps, 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
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)
30 void CreateSpotLight( SSpotLight *pSpotLight, uint16_ iDiameter, uint16_ nColorCount )
33 int16_ iHeight, iWidth;
35 pSpotLight->nDiameter = iDiameter;
37 printf( "%s: Light Diameter: %d\n", progclass, pSpotLight->nDiameter );
40 pSpotLight->aLightMap = calloc( pSpotLight->nDiameter * pSpotLight->nDiameter, sizeof(uint8_) );
41 memset( pSpotLight->aLightMap, 0, pSpotLight->nDiameter * pSpotLight->nDiameter );
43 /* The falloff max values... 3/4 of the entire lightmap. */
44 pSpotLight->nRadius = (uint16_)(pSpotLight->nDiameter / 2.5F);
46 for( iHeight=-pSpotLight->nRadius; iHeight<pSpotLight->nRadius; iHeight++ )
47 for( iWidth=-pSpotLight->nRadius; iWidth<pSpotLight->nRadius; iWidth++ )
49 nDelta = ( nColorCount * 2.5F ) - ( ( sqrt( pow( iWidth+0.5F, 2 ) + pow( iHeight+0.5F, 2 ) ) / pSpotLight->nRadius ) * ( nColorCount * 2.5F ) );
50 nDelta += nColorCount;
51 if( nDelta >= ( nColorCount * 2 ) ) nDelta = ( nColorCount * 2 ) - 1;
52 if( nDelta >= nColorCount )
53 pSpotLight->aLightMap[ ( ( iHeight + (pSpotLight->nDiameter/2) ) * pSpotLight->nDiameter ) + iWidth + (pSpotLight->nDiameter/2) ] = (uint8_)nDelta;
56 /* The actual lightmap... 1/2 of the entire lightmap. */
57 pSpotLight->nRadius = pSpotLight->nDiameter / 4;
59 for( iHeight=-pSpotLight->nRadius; iHeight<pSpotLight->nRadius; iHeight++ )
60 for( iWidth=-pSpotLight->nRadius; iWidth<pSpotLight->nRadius; iWidth++ )
62 nDelta = nColorCount - ( ( sqrt( pow( iWidth+0.5F, 2 ) + pow( iHeight+0.5F, 2 ) ) / pSpotLight->nRadius ) * ( nColorCount - 1 ) );
64 pSpotLight->aLightMap[ ( ( iHeight + (pSpotLight->nDiameter/2) ) * pSpotLight->nDiameter ) + iWidth + (pSpotLight->nDiameter/2) ] = (uint8_)nDelta;
67 CreateTables( pSpotLight );
69 pSpotLight->nRadius = pSpotLight->nDiameter / 2; /* Now set the radius back to what it should be. */
70 pSpotLight->nAngleX = RANDOM() % pSpotLight->nDegreeCount;
71 pSpotLight->nAngleY = RANDOM() % pSpotLight->nDegreeCount;
72 pSpotLight->nVelocityX = ( RANDOM() % 3 ) + 1;
73 pSpotLight->nVelocityY = ( RANDOM() % 3 ) + 1;
77 void CreateTables( SSpotLight *pSpotLight )
82 pSpotLight->nDegreeCount = get_integer_resource( "degrees", "Integer" );
83 if( pSpotLight->nDegreeCount < 180 ) pSpotLight->nDegreeCount = 180; /* Less than 180 will show trails in higher resolutions. */
85 printf( "%s: Using a %d degree circle.\n", progclass, pSpotLight->nDegreeCount );
88 pSpotLight->aSinTable = calloc( pSpotLight->nDegreeCount, sizeof(double) );
90 /* This funtion builds the Sine Lookup Tables. */
91 nUnit = (double)( PI * 2.0F ) / (double)( pSpotLight->nDegreeCount );
93 for( iDegree=0; iDegree<pSpotLight->nDegreeCount; iDegree++)
94 pSpotLight->aSinTable[ iDegree ] = sin( nUnit * (double)iDegree );
98 void CalcLightPos( SSpotLight *pSpotLight, uint16_ *pXPos, uint16_ *pYPos )
100 pSpotLight->nVelocityX += ( RANDOM() % 2 ) ? 0.05F : -0.05F;
101 if( pSpotLight->nVelocityX < 1 ) pSpotLight->nVelocityX = 1;
102 else if( pSpotLight->nVelocityX > 3 ) pSpotLight->nVelocityX = 3;
104 pSpotLight->nVelocityX += ( RANDOM() % 2 ) ? 0.05F : -0.05F;
105 if( pSpotLight->nVelocityY < 1 ) pSpotLight->nVelocityX = 1;
106 else if( pSpotLight->nVelocityY > 3 ) pSpotLight->nVelocityX = 3;
108 pSpotLight->nAngleX += pSpotLight->nVelocityX;
109 if( pSpotLight->nAngleX >= pSpotLight->nDegreeCount ) pSpotLight->nAngleX -= pSpotLight->nDegreeCount;
111 pSpotLight->nAngleY += pSpotLight->nVelocityY;
112 if( pSpotLight->nAngleY >= pSpotLight->nDegreeCount ) pSpotLight->nAngleY -= pSpotLight->nDegreeCount;
114 *pXPos = (uint16_)( ( pSpotLight->iWinXCenter - pSpotLight->nRadius ) * pSpotLight->aSinTable[ (uint16_)pSpotLight->nAngleX ] ) + pSpotLight->iWinXCenter;
115 *pYPos = (uint16_)( ( pSpotLight->iWinYCenter - pSpotLight->nRadius ) * pSpotLight->aSinTable[ (uint16_)pSpotLight->nAngleY ] ) + pSpotLight->iWinYCenter;
117 /* Offset to upper left hand corner. */
118 *pXPos -= pSpotLight->nRadius;
119 *pYPos -= pSpotLight->nRadius;
123 void CreateBumps( SBumps *pBumps, Display *pNewDisplay, Window NewWin )
125 XWindowAttributes XWinAttribs;
128 uint16_ iWidth, iHeight;
131 XGetWindowAttributes( pNewDisplay, NewWin, &XWinAttribs );
132 pBumps->iWinWidth = XWinAttribs.width;
133 pBumps->iWinHeight = XWinAttribs.height;
134 pBumps->SpotLight.iWinXCenter = XWinAttribs.width / 2;
135 pBumps->SpotLight.iWinYCenter = XWinAttribs.height / 2;
136 pBumps->pDisplay = pNewDisplay;
137 pBumps->Win = NewWin;
139 pBumps->pXImage = XCreateImage( pBumps->pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
140 pBumps->iWinWidth, pBumps->iWinHeight, BitmapPad( pBumps->pDisplay ), 0 );
141 pBumps->pXImage->data = calloc( pBumps->pXImage->bytes_per_line * pBumps->pXImage->height, sizeof(int8_) );
143 GCValues.function = GXcopy;
144 GCValues.subwindow_mode = IncludeInferiors;
145 nGCFlags = GCForeground | GCFunction;
146 if( use_subwindow_mode_p( XWinAttribs.screen, pBumps->Win ) ) /* See grabscreen.c */
147 nGCFlags |= GCSubwindowMode;
148 pBumps->GraphicsContext = XCreateGC( pBumps->pDisplay, pBumps->Win, nGCFlags, &GCValues );
150 SetPalette( pBumps, &XWinAttribs );
151 iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 3;
152 CreateSpotLight( &pBumps->SpotLight, iDiameter, pBumps->nColorCount );
153 InitBumpMap( pBumps, &XWinAttribs );
155 /* Clear the image. */
156 if (pBumps->aXColors[ 0 ].pixel == 0)
157 memset (pBumps->pXImage->data, 0,
158 pBumps->pXImage->bytes_per_line * pBumps->pXImage->height);
160 for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
161 for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
162 XPutPixel( pBumps->pXImage, iWidth, iHeight,
163 pBumps->aXColors[ 0 ].pixel );
164 XSetWindowBackground( pBumps->pDisplay, pBumps->Win,
165 pBumps->aXColors[ 0 ].pixel );
166 XClearWindow (pBumps->pDisplay, pBumps->Win);
170 void SetPalette( SBumps *pBumps, XWindowAttributes *pXWinAttribs )
173 char *sColor; /* Spotlight Color */
177 sColor = get_string_resource( "color", "Color" );
179 Color.red = RANDOM() % 0xFFFF;
180 Color.green = RANDOM() % 0xFFFF;
181 Color.blue = RANDOM() % 0xFFFF;
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->SpotLight, &nLightXPos, &nLightYPos );
315 for( iHeight=nLightYPos, iLightHeight=0; iLightHeight<pBumps->SpotLight.nDiameter; iHeight++, iLightHeight++ )
317 pBOffset = pBumps->aBumpMap + ( iHeight * pBumps->iWinWidth );
318 pLOffset = pBumps->SpotLight.aLightMap + ( iLightHeight * pBumps->SpotLight.nDiameter );
319 for( iWidth=nLightXPos, iLightWidth=0; iLightWidth<pBumps->SpotLight.nDiameter; iWidth++, iLightWidth++ )
321 if( pLOffset[ iLightWidth ] )
323 nX = pBOffset[ iWidth + 1 ] - pBOffset[ iWidth ] + iLightWidth;
324 nY = pBOffset[ iWidth + pBumps->iWinWidth ] - pBOffset[ iWidth ] + iLightHeight;
327 else if( nX >= pBumps->SpotLight.nDiameter ) nX = pBumps->SpotLight.nDiameter - 1;
330 else if( nY >= pBumps->SpotLight.nDiameter ) nY = pBumps->SpotLight.nDiameter - 1;
332 nColor = pBumps->SpotLight.aLightMap[ ( nY * pBumps->SpotLight.nDiameter ) + nX ];
333 if( nColor >= pBumps->nColorCount )
336 if( pLOffset[ iLightWidth ] >= pBumps->nColorCount )
337 if( nColor > pLOffset[ iLightWidth ] - pBumps->nColorCount )
338 nColor = pLOffset[ iLightWidth ] - pBumps->nColorCount;
340 XPutPixel( pBumps->pXImage, iWidth, iHeight, pBumps->aXColors[ nColor ].pixel );
343 XPutPixel( pBumps->pXImage, iWidth, iHeight, pBumps->aXColors[ 0 ].pixel );
347 XPutImage( pBumps->pDisplay, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, nLightXPos, nLightYPos, nLightXPos, nLightYPos, pBumps->SpotLight.nDiameter, pBumps->SpotLight.nDiameter );
348 XSync( pBumps->pDisplay, False );
352 void DestroyBumps( SBumps *pBumps )
354 DestroySpotLight( &pBumps->SpotLight );
355 free( pBumps->aXColors );
356 free( pBumps->aBumpMap );
357 XDestroyImage( pBumps->pXImage );
361 /* All messages to the screensaver are processed here. */
362 void screenhack( Display *pDisplay, Window Win )
367 time_t Time = time( NULL );
371 CreateBumps( &Bumps, pDisplay, Win );
372 iDelay = get_integer_resource( "delay", "Integer" );
376 screenhack_handle_events( pDisplay );
382 if( Time - time( NULL ) )
384 printf( "FPS: %d\n", iFrame );
391 DestroyBumps( &Bumps );
396 * End of Module: "Bumps.cpp"