1 /* -*- mode: C; tab-width: 4 -*-
2 * Bumps, Copyright (c) 2002, 2006 Shane Smit <CodeWeaver@DigitalLoom.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
16 * This is typical bump-mapping. The actual bump map is generated by a screen
17 * grab. The light source is represented by a spotlight of random color. This
18 * spotlight randomly traverses the bump map in a sinus pattern.
20 * Essentially, it 3D-izes your desktop, based on color intensity.
22 * Modification History:
23 * [10/01/99] - Shane Smit: Creation
24 * [10/08/99] - Shane Smit: Port to C. (Ick)
25 * [03/08/02] - Shane Smit: New movement code.
26 * [09/12/02] - Shane Smit: MIT-SHM XImages.
27 * Thanks to Kennett Galbraith <http://www.Alpha-II.com/>
28 * for code optimization.
34 #include "screenhack.h"
36 #ifdef HAVE_XSHM_EXTENSION
38 #endif /* HAVE_XSHM_EXTENSION */
43 #define RANDOM() ((int) (random() & 0X7FFFFFFFL))
45 typedef unsigned char BOOL;
50 static const char *bumps_defaults [] = {
60 #ifdef __sgi /* really, HAVE_READ_DISPLAY_EXTENSION */
63 #ifdef HAVE_XSHM_EXTENSION
65 #endif /* HAVE_XSHM_EXTENSION */
67 "*ignoreRotation: True",
68 "*rotateImages: True",
73 static XrmOptionDescRec bumps_options [] = {
74 { "-color", ".color", XrmoptionSepArg, 0 },
75 { "-colorcount", ".colorcount", XrmoptionSepArg, 0 },
76 { "-duration", ".duration", XrmoptionSepArg, 0 },
77 { "-delay", ".delay", XrmoptionSepArg, 0 },
78 { "-soften", ".soften", XrmoptionSepArg, 0 },
79 { "-invert", ".invert", XrmoptionNoArg, "TRUE" },
80 #ifdef HAVE_XSHM_EXTENSION
81 { "-shm", ".useSHM", XrmoptionNoArg, "True" },
82 { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
83 #endif /* HAVE_XSHM_EXTENSION */
89 /* This structure handles everything to do with the spotlight, and is designed to be
90 * a member of TBumps. */
94 uint16_t nFalloffDiameter, nFalloffRadius;
95 uint16_t nLightDiameter, nLightRadius;
96 float nAccelX, nAccelY;
98 float nVelocityX, nVelocityY;
104 /* The entire program's operation is contained within this structure. */
107 /* XWindows specific variables. */
114 unsigned long *aColors;
116 #ifdef HAVE_XSHM_EXTENSION
117 XShmSegmentInfo XShmInfo;
119 #endif /* HAVE_XSHM_EXTENSION */
121 uint8_t nColorCount; /* Number of colors used. */
122 uint8_t bytesPerPixel;
123 uint16_t iWinWidth, iWinHeight;
124 uint16_t *aBumpMap; /* The actual bump map. */
125 SSpotLight SpotLight;
131 async_load_state *img_loader;
135 static void SetPalette(Display *, SBumps *, XWindowAttributes * );
136 static void InitBumpMap(Display *, SBumps *, XWindowAttributes * );
137 static void InitBumpMap_2(Display *, SBumps *);
138 static void SoftenBumpMap( SBumps * );
143 /* This function pointer will point to the appropriate PutPixel*() function below. */
144 static void (*MyPutPixel)( int8_t *, uint32_t );
146 static void PutPixel32( int8_t *pData, uint32_t pixel )
148 *(uint32_t *)pData = pixel;
151 static void PutPixel24( int8_t *pData, uint32_t pixel )
153 pData[ 2 ] = ( pixel & 0x00FF0000 ) >> 16;
154 pData[ 1 ] = ( pixel & 0x0000FF00 ) >> 8;
155 pData[ 0 ] = ( pixel & 0x000000FF );
158 static void PutPixel16( int8_t *pData, uint32_t pixel )
160 *(uint16_t *)pData = (uint16_t)pixel;
163 static void PutPixel8( int8_t *pData, uint32_t pixel )
165 *(uint8_t *)pData = (uint8_t)pixel;
168 /* Creates the light map, which is a circular image... going from black around the edges
169 * to white in the center. */
170 static void CreateSpotLight( SSpotLight *pSpotLight, uint16_t iDiameter, uint16_t nColorCount )
173 int16_t iDistX, iDistY;
176 pSpotLight->nFalloffDiameter = iDiameter;
177 pSpotLight->nFalloffRadius = pSpotLight->nFalloffDiameter / 2;
178 pSpotLight->nLightDiameter = iDiameter / 2;
179 pSpotLight->nLightRadius = pSpotLight->nLightDiameter / 2;
181 printf( "%s: Falloff Diameter: %d\n", progclass, pSpotLight->nFalloffDiameter );
182 printf( "%s: Spot Light Diameter: %d\n", progclass, pSpotLight->nLightDiameter );
185 pSpotLight->aLightMap = malloc( pSpotLight->nLightDiameter * pSpotLight->nLightDiameter * sizeof(uint8_t) );
187 pLOffset = pSpotLight->aLightMap;
188 for( iDistY=-pSpotLight->nLightRadius; iDistY<pSpotLight->nLightRadius; ++iDistY )
190 for( iDistX=-pSpotLight->nLightRadius; iDistX<pSpotLight->nLightRadius; ++iDistX )
192 nDist = sqrt( pow( iDistX+0.5F, 2 ) + pow( iDistY+0.5F, 2 ) );
193 if( nDist / pSpotLight->nLightRadius <= 1.0f )
194 *pLOffset = (uint8_t)(nColorCount - ( ( nDist / pSpotLight->nLightRadius ) * ( nColorCount - 1 ) ));
202 /* Initialize movement variables. */
203 pSpotLight->nAccelX = 0;
204 pSpotLight->nAccelY = 0;
205 pSpotLight->nVelocityX = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax;
206 pSpotLight->nVelocityY = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax;
210 /* Calculates the position of the spot light on the screen. */
211 static void CalcLightPos( SBumps *pBumps )
213 SSpotLight *pSpotLight = &pBumps->SpotLight;
217 if( pSpotLight->nXPos < pSpotLight->nFalloffRadius ) nGravity = 1.0f;
218 else if( pSpotLight->nXPos > pBumps->iWinWidth - pSpotLight->nFalloffRadius ) nGravity = -1.0f;
219 else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f;
221 pSpotLight->nAccelX += nGravity * ( pSpotLight->nAccelMax / 5.0f );
222 if( pSpotLight->nAccelX < -pSpotLight->nAccelMax ) pSpotLight->nAccelX = -pSpotLight->nAccelMax;
223 else if( pSpotLight->nAccelX > pSpotLight->nAccelMax ) pSpotLight->nAccelX = pSpotLight->nAccelMax;
225 pSpotLight->nVelocityX += pSpotLight->nAccelX;
226 if( pSpotLight->nVelocityX < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = -pSpotLight->nVelocityMax;
227 else if( pSpotLight->nVelocityX > pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = pSpotLight->nVelocityMax;
229 pSpotLight->nXPos += pSpotLight->nVelocityX;
232 if( pSpotLight->nYPos < pSpotLight->nFalloffRadius ) nGravity = 1.0f;
233 else if( pSpotLight->nYPos > pBumps->iWinHeight - pSpotLight->nFalloffRadius ) nGravity = -1.0f;
234 else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f;
236 pSpotLight->nAccelY += nGravity * ( pSpotLight->nAccelMax / 5.0f );
237 if( pSpotLight->nAccelY < -pSpotLight->nAccelMax ) pSpotLight->nAccelY = -pSpotLight->nAccelMax;
238 else if( pSpotLight->nAccelY > pSpotLight->nAccelMax ) pSpotLight->nAccelY = pSpotLight->nAccelMax;
240 pSpotLight->nVelocityY += pSpotLight->nAccelY;
241 if( pSpotLight->nVelocityY < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = -pSpotLight->nVelocityMax;
242 else if( pSpotLight->nVelocityY > pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = pSpotLight->nVelocityMax;
244 pSpotLight->nYPos += pSpotLight->nVelocityY;
248 /* Main initialization function. */
249 static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin )
251 XWindowAttributes XWinAttribs;
256 /* Make size and velocity a function of window size, so it appears the same at 100x60 as it does in 3200x1200. */
257 XGetWindowAttributes( dpy, NewWin, &XWinAttribs );
258 pBumps->iWinWidth = XWinAttribs.width;
259 pBumps->iWinHeight = XWinAttribs.height;
260 pBumps->SpotLight.nXPos = XWinAttribs.width / 2.0f;
261 pBumps->SpotLight.nYPos = XWinAttribs.height / 2.0f;
262 pBumps->SpotLight.nVelocityMax = ( ( XWinAttribs.width < XWinAttribs.height ) ? XWinAttribs.width : XWinAttribs.height ) / 140.0f;
263 pBumps->SpotLight.nAccelMax = pBumps->SpotLight.nVelocityMax / 10.0f;
265 pBumps->Win = NewWin;
266 pBumps->screen = XWinAttribs.screen;
267 pBumps->pXImage = NULL;
269 iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 2;
271 /* jwz: sometimes we get tearing if this lands on the wrong bounaary;
272 constraining it to be a multiple of 8 seems to fix it. */
273 iDiameter = ((iDiameter+7)/8)*8;
275 #ifdef HAVE_XSHM_EXTENSION
276 pBumps->bUseShm = get_boolean_resource(dpy, "useSHM", "Boolean" );
278 if( pBumps->bUseShm )
280 pBumps->pXImage = create_xshm_image( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth,
281 ZPixmap, NULL, &pBumps->XShmInfo, iDiameter, iDiameter );
282 if( !pBumps->pXImage )
284 fprintf( stderr, "%s: Unable to create XShmImage.\n", progname );
285 pBumps->bUseShm = False;
288 #endif /* HAVE_XSHM_EXTENSION */
289 if( !pBumps->pXImage )
291 pBumps->pXImage = XCreateImage( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth,
292 ZPixmap, 0, NULL, iDiameter, iDiameter, BitmapPad( pBumps->dpy ), 0 );
293 pBumps->pXImage->data = malloc( pBumps->pXImage->bytes_per_line * pBumps->pXImage->height * sizeof(int8_t) );
296 /* For speed, access the XImage data directly using my own PutPixel routine. */
297 switch( pBumps->pXImage->bits_per_pixel )
300 pBumps->bytesPerPixel = 4;
301 MyPutPixel = PutPixel32;
305 pBumps->bytesPerPixel = 3;
306 MyPutPixel = PutPixel24;
310 pBumps->bytesPerPixel = 2;
311 MyPutPixel = PutPixel16;
315 pBumps->bytesPerPixel = 1;
316 MyPutPixel = PutPixel8;
320 fprintf( stderr, "%s: Unknown XImage depth.", progname );
321 #ifdef HAVE_XSHM_EXTENSION
322 if( pBumps->bUseShm )
323 destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo );
325 #endif /* HAVE_XSHM_EXTENSION */
326 XDestroyImage( pBumps->pXImage );
330 GCValues.function = GXcopy;
331 GCValues.subwindow_mode = IncludeInferiors;
332 nGCFlags = GCFunction;
333 if( use_subwindow_mode_p( XWinAttribs.screen, pBumps->Win ) ) /* See grabscreen.c */
334 nGCFlags |= GCSubwindowMode;
335 pBumps->GraphicsContext = XCreateGC( pBumps->dpy, pBumps->Win, nGCFlags, &GCValues );
337 SetPalette(dpy, pBumps, &XWinAttribs );
338 CreateSpotLight( &pBumps->SpotLight, iDiameter, pBumps->nColorCount );
339 InitBumpMap(dpy, pBumps, &XWinAttribs );
343 /* Creates a specialized phong shade palette. */
344 static void SetPalette(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAttribs )
348 char *sColor; /* Spotlight Color */
351 sColor = get_string_resource(dpy, "color", "Color" );
353 BaseColor.red = RANDOM() % 0xFFFF;
354 BaseColor.green = RANDOM() % 0xFFFF;
355 BaseColor.blue = RANDOM() % 0xFFFF;
357 /* Make one color full intesity to avoid dark spotlights. */
358 switch( RANDOM() % 3 )
360 case 0: BaseColor.red = 0xFFFF; break;
361 case 1: BaseColor.green = 0xFFFF; break;
362 case 2: BaseColor.blue = 0xFFFF; break;
365 if( strcasecmp( sColor, "random" ) && !XParseColor( pBumps->dpy, pXWinAttribs->colormap, sColor, &BaseColor ) )
366 fprintf( stderr, "%s: color %s not found in database. Choosing random...\n", progname, sColor );
369 printf( "%s: Spotlight color is <%d,%d,%d> RGB.\n", progclass, BaseColor.red, BaseColor.green, BaseColor.blue );
372 pBumps->nColorCount = get_integer_resource(dpy, "colorcount", "Integer" );
373 if( pBumps->nColorCount < 2 ) pBumps->nColorCount = 2;
374 if( pBumps->nColorCount > 128 ) pBumps->nColorCount = 128;
376 pBumps->aColors = malloc( pBumps->nColorCount * sizeof(unsigned long) );
378 /* Creates a phong shade: / BaseColor \ Index/ColorCount
379 * PhongShade = | ------------ | Index + ( 65535 - BaseColor )^
381 pBumps->nColorCount--;
382 for( iColor=0; iColor<=pBumps->nColorCount; iColor++ )
384 Color.red = (uint16_t)( ( ( BaseColor.red / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.red, iColor/(double)pBumps->nColorCount ) );
385 Color.green = (uint16_t)( ( ( BaseColor.green / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.green, iColor/(double)pBumps->nColorCount ) );
386 Color.blue = (uint16_t)( ( ( BaseColor.blue / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.blue, iColor/(double)pBumps->nColorCount ) );
388 if( !XAllocColor( pBumps->dpy, pXWinAttribs->colormap, &Color ) )
390 XFreeColors( pBumps->dpy, pXWinAttribs->colormap, pBumps->aColors, iColor, 0 );
391 free( pBumps->aColors );
392 pBumps->aColors = malloc( pBumps->nColorCount * sizeof(unsigned long) );
393 pBumps->nColorCount--;
397 pBumps->aColors[ iColor ] = Color.pixel;
399 pBumps->nColorCount++;
402 printf( "%s: Allocated %d colors.\n", progclass, pBumps->nColorCount );
405 XSetWindowBackground( pBumps->dpy, pBumps->Win, pBumps->aColors[ 0 ] );
409 /* Grabs the current contents of the window to use an intensity-based bump map. */
410 static void InitBumpMap(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAttribs )
412 pBumps->xColors = (XColor*)malloc( pBumps->iWinWidth * sizeof(XColor) );
414 if (pBumps->source) abort();
415 pBumps->source = XCreatePixmap(pBumps->dpy, pBumps->Win,
416 pXWinAttribs->width, pXWinAttribs->height,
417 pXWinAttribs->depth);
418 pBumps->img_loader = load_image_async_simple (0, pXWinAttribs->screen,
419 pBumps->Win, pBumps->source, 0, 0);
422 static void InitBumpMap_2(Display *dpy, SBumps *pBumps)
424 XImage *pScreenImage;
427 uint16_t iWidth, iHeight;
431 double softenMultiplier = 1.0f;
432 BOOL bInvert = (BOOL)get_boolean_resource(dpy, "invert", "Boolean" );
433 XWindowAttributes XWinAttribs;
434 XGetWindowAttributes( pBumps->dpy, pBumps->Win, &XWinAttribs );
436 pBumps->start_time = time ((time_t) 0);
438 pScreenImage = XGetImage( pBumps->dpy, pBumps->source, 0, 0,
439 pBumps->iWinWidth, pBumps->iWinHeight,
441 /* XFreePixmap (pBumps->dpy, pBumps->source);
442 pBumps->source = 0;*/
444 XSetWindowBackground( pBumps->dpy, pBumps->Win, pBumps->aColors[ 0 ] );
445 XClearWindow (pBumps->dpy, pBumps->Win);
446 XSync (pBumps->dpy, 0);
448 pBumps->aBumpMap = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) );
450 nSoften = get_integer_resource(dpy, "soften", "Integer" );
452 softenMultiplier *= 1.0f + ( 1.0f / 3.0f ); /* Softening takes the max height down, so scale up to compensate. */
453 maxHeight = pBumps->SpotLight.nLightRadius * softenMultiplier;
454 nAverager = maxHeight ? ( 3 * 0xFFFF ) / maxHeight : 0;
456 pBump = pBumps->aBumpMap;
457 if( bInvert ) /* Funny, it's actually the 'else' that inverts the bump map... */
459 for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
461 pColor = pBumps->xColors;
462 for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
463 (pColor++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight );
465 XQueryColors( pBumps->dpy, XWinAttribs.colormap, pBumps->xColors, pBumps->iWinWidth );
467 pColor = pBumps->xColors;
468 for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump )
469 *pBump = ( nAverager ? ( pColor->red + pColor->green + pColor->blue ) / nAverager : 0 );
474 for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
476 pColor = pBumps->xColors;
477 for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
478 (pColor++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight );
480 XQueryColors( pBumps->dpy, XWinAttribs.colormap, pBumps->xColors, pBumps->iWinWidth );
482 pColor = pBumps->xColors;
483 for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump )
484 *pBump = ( maxHeight - ( nAverager ? ( pColor->red + pColor->green + pColor->blue ) / nAverager : 0 ) );
488 XDestroyImage( pScreenImage );
490 nSoften = get_integer_resource(dpy, "soften", "Integer" );
492 if( nSoften ) printf( "%s: Softening Bump Map %d time(s)...\n", progclass, nSoften );
495 SoftenBumpMap( pBumps );
497 /* free( pBumps->xColors );
498 pBumps->xColors = 0;*/
501 /* Soften the bump map. This is to avoid pixelated-looking ridges.
502 * |-----|-----|-----|
503 * | 0% |12.5%| 0% | The adjacent pixels are averaged together
504 * |-----|-----|-----| first. Then than value is averaged with
505 * |12.5%| 50% |12.5%| the pixel is question. This essentially weights
506 * |-----|-----|-----| each pixel as shown on the left.
508 * |-----|-----|-----|
510 static void SoftenBumpMap( SBumps *pBumps )
512 uint16_t *pOffset, *pTOffset;
514 uint32_t iWidth, iHeight;
515 uint16_t *aTempBuffer = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) );
517 pOffset = pBumps->aBumpMap;
518 pTOffset = aTempBuffer;
519 for( iHeight=pBumps->iWinHeight; iHeight; --iHeight )
521 for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pOffset, ++pTOffset )
523 if( iHeight==pBumps->iWinHeight || iHeight==1 ||
524 iWidth==pBumps->iWinWidth || iWidth==1 )
530 nHeight = pOffset[ -pBumps->iWinWidth ];
531 nHeight += pOffset[ 1 ];
532 nHeight += pOffset[ pBumps->iWinWidth ];
533 nHeight += pOffset[ -1 ];
535 nHeight += pOffset[ 0 ];
541 memcpy( pBumps->aBumpMap, aTempBuffer, pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) );
546 /* This is where we slap down some pixels... */
547 static void Execute( SBumps *pBumps )
549 int32_t nLightXPos, nLightYPos;
550 int32_t iScreenX, iScreenY;
551 int32_t iLightX, iLightY;
556 int32_t nLightOffsetFar = pBumps->SpotLight.nFalloffDiameter - pBumps->SpotLight.nLightRadius;
558 CalcLightPos( pBumps );
560 /* Offset to upper left hand corner. */
561 nLightXPos = pBumps->SpotLight.nXPos - pBumps->SpotLight.nFalloffRadius;
562 nLightYPos = pBumps->SpotLight.nYPos - pBumps->SpotLight.nFalloffRadius;
564 for( iScreenY=nLightYPos, iLightY=-pBumps->SpotLight.nLightRadius; iLightY<nLightOffsetFar; ++iScreenY, ++iLightY )
566 if( iScreenY < 0 ) continue;
567 else if( iScreenY >= pBumps->iWinHeight ) break;
569 /* warning: pointer targets in assignment differ in signedness
570 Should pDOffset be a int8? I can't tell. -jwz, 22-Jul-2003 */
571 pDOffset = (int8_t *) &pBumps->pXImage->data[ (iLightY+pBumps->SpotLight.nLightRadius) * pBumps->pXImage->bytes_per_line ];
572 pBOffset = pBumps->aBumpMap + ( iScreenY * pBumps->iWinWidth ) + nLightXPos;
573 for( iScreenX=nLightXPos, iLightX=-pBumps->SpotLight.nLightRadius; iLightX<nLightOffsetFar; ++iScreenX, ++iLightX, ++pBOffset, pDOffset+=pBumps->bytesPerPixel )
575 if( iScreenX < 0 ) continue;
576 else if( iScreenX >= pBumps->iWinWidth ) break;
577 else if( iScreenY == 0 || iScreenY >= pBumps->iWinHeight-2 ||
578 iScreenX == 0 || iScreenX >= pBumps->iWinWidth-2 )
580 MyPutPixel( pDOffset, pBumps->aColors[ 0 ] );
584 /* That's right folks, all the magic of bump mapping occurs in these two lines. (kinda disappointing, isn't it?) */
585 nX = ( pBOffset[ 1 ] - pBOffset[ 0 ] ) + iLightX;
586 nY = ( pBOffset[ pBumps->iWinWidth ] - pBOffset[ 0 ] ) + iLightY;
588 if( nX<0 || nX>=pBumps->SpotLight.nLightDiameter
589 || nY<0 || nY>=pBumps->SpotLight.nLightDiameter )
591 MyPutPixel( pDOffset, pBumps->aColors[ 0 ] );
595 nColor = pBumps->SpotLight.aLightMap[ ( nY * pBumps->SpotLight.nLightDiameter ) + nX ];
596 MyPutPixel( pDOffset, pBumps->aColors[ nColor ] );
600 /* Allow the spotlight to go *slightly* off the screen by clipping the XImage. */
601 iLightX = iLightY = 0; /* Use these for XImages X and Y now. */
602 nX = nY = pBumps->SpotLight.nFalloffDiameter; /* Use these for XImage width and height now. */
605 iLightX = -nLightXPos;
609 else if( nLightXPos + nX >= pBumps->iWinWidth )
611 nX -= ( nLightXPos + nX ) - pBumps->iWinWidth;
616 iLightY = -nLightYPos;
620 else if( nLightYPos + nY >= pBumps->iWinHeight )
622 nY -= ( nLightYPos + nY ) - pBumps->iWinHeight;
625 #ifdef HAVE_XSHM_EXTENSION
626 if( pBumps->bUseShm )
627 XShmPutImage( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos,
630 #endif /* HAVE_XSHM_EXTENSION */
631 XPutImage( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos,
636 static void DestroySpotLight( SSpotLight *pSpotLight ) { free( pSpotLight->aLightMap ); }
639 static void DestroyBumps( SBumps *pBumps )
641 DestroySpotLight( &pBumps->SpotLight );
642 free( pBumps->aColors );
643 free( pBumps->aBumpMap );
644 #ifdef HAVE_XSHM_EXTENSION
645 if( pBumps->bUseShm )
646 destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo );
648 #endif /* HAVE_XSHM_EXTENSION */
649 XDestroyImage( pBumps->pXImage );
653 /* All messages to the screensaver are processed here. */
655 bumps_init (Display *dpy, Window Win)
657 SBumps *Bumps = (SBumps *) calloc (1, sizeof(SBumps));
660 time_t Time = time( NULL );
664 CreateBumps( Bumps, dpy, Win );
665 Bumps->delay = get_integer_resource(dpy, "delay", "Integer" );
666 Bumps->duration = get_integer_resource (dpy, "duration", "Seconds");
667 if (Bumps->delay < 0) Bumps->delay = 0;
668 if (Bumps->duration < 1) Bumps->duration = 1;
669 Bumps->start_time = time ((time_t) 0);
674 bumps_draw (Display *dpy, Window window, void *closure)
676 SBumps *Bumps = (SBumps *) closure;
678 if (Bumps->img_loader) /* still loading */
680 Bumps->img_loader = load_image_async_simple (Bumps->img_loader, 0, 0, 0, 0, 0);
681 if (! Bumps->img_loader) /* just finished */
682 InitBumpMap_2(dpy, Bumps);
686 if (!Bumps->img_loader &&
687 Bumps->start_time + Bumps->duration < time ((time_t) 0)) {
688 Bumps->img_loader = load_image_async_simple (0, Bumps->screen,
689 Bumps->Win, Bumps->source,
697 if( Time - time( NULL ) )
699 printf( "FPS: %d\n", iFrame );
709 bumps_reshape (Display *dpy, Window window, void *closure,
710 unsigned int w, unsigned int h)
715 bumps_event (Display *dpy, Window window, void *closure, XEvent *event)
717 SBumps *Bumps = (SBumps *) closure;
718 if (screenhack_event_helper (dpy, window, event))
720 Bumps->start_time = 0;
728 bumps_free (Display *dpy, Window window, void *closure)
730 SBumps *Bumps = (SBumps *) closure;
731 DestroyBumps( Bumps );
735 XSCREENSAVER_MODULE ("Bumps", bumps)