From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / bumps.c
index 2f510f5a9b5a5b15487a21ddb4e457a5e953b223..fa728e6c0a247a6ae846f272fe06176d410ead58 100644 (file)
  *  Essentially, it 3D-izes your desktop, based on color intensity.
  *
  * Modification History:
- *  [10/01/99] - Shane Smit: Creation
- *  [10/08/99] - Shane Smit: Port to C. (Ick)
- *  [03/08/02] - Shane Smit: New movement code.
- *  [09/12/02] - Shane Smit: MIT-SHM XImages.
- *                                                      Thanks to Kennett Galbraith <http://www.Alpha-II.com/>
- *                                                      for code optimization.
+ *  [10/01/1999] - Shane Smit: Creation
+ *  [10/08/1999] - Shane Smit: Port to C. (Ick)
+ *  [03/08/2002] - Shane Smit: New movement code.
+ *  [09/12/2002] - Shane Smit: MIT-SHM XImages.
+ *                             Thanks to Kennett Galbraith <http://www.Alpha-II.com/>
+ *                             for code optimization.
+ *  [10/09/2016] - Dave Odell: Updated for new xshm.c.
+ *                             Y2K compliance.
  */
 
-#include "bumps.h"
+
+#include <math.h>
+#include <time.h>
+#include <inttypes.h>
+#include "screenhack.h"
+#include "xshm.h"
+
+
+/* Defines: */
+/* #define VERBOSE */
+#define RANDOM() ((int) (random() & 0X7FFFFFFFL))
+
+typedef unsigned char  BOOL;
+
+
+/* Globals: */
+
+static const char *bumps_defaults [] = {
+  ".background: black",
+  ".foreground: white",
+  "*fpsSolid:  true",
+  "*color:             random",
+  "*colorcount:        64",
+  "*delay:             30000",
+  "*duration:  120",
+  "*soften:            1",
+  "*invert:            FALSE",
+#ifdef __sgi    /* really, HAVE_READ_DISPLAY_EXTENSION */
+  "*visualID:  Best",
+#endif
+#ifdef HAVE_XSHM_EXTENSION
+  "*useSHM:            True",
+#endif /* HAVE_XSHM_EXTENSION */
+#ifdef HAVE_MOBILE
+  "*ignoreRotation: True",
+  "*rotateImages:   True",
+#endif
+  0
+};
+
+static XrmOptionDescRec bumps_options [] = {
+  { "-color",          ".color",               XrmoptionSepArg, 0 },
+  { "-colorcount",     ".colorcount",  XrmoptionSepArg, 0 },
+  { "-duration",       ".duration",    XrmoptionSepArg, 0 },
+  { "-delay",          ".delay",               XrmoptionSepArg, 0 },
+  { "-soften",         ".soften",              XrmoptionSepArg, 0 },
+  { "-invert",         ".invert",              XrmoptionNoArg, "TRUE" },
+#ifdef HAVE_XSHM_EXTENSION
+  { "-shm",                    ".useSHM",              XrmoptionNoArg, "True" },
+  { "-no-shm",         ".useSHM",              XrmoptionNoArg, "False" },
+#endif /* HAVE_XSHM_EXTENSION */
+
+  { 0, 0, 0, 0 }
+};
+
+
+/* This structure handles everything to do with the spotlight, and is designed to be
+ * a member of TBumps. */
+typedef struct
+{
+       uint8_t *aLightMap;
+       uint16_t nFalloffDiameter, nFalloffRadius;
+       uint16_t nLightDiameter, nLightRadius;
+       float nAccelX, nAccelY;
+       float nAccelMax;
+       float nVelocityX, nVelocityY;
+       float nVelocityMax;
+       float nXPos, nYPos;
+} SSpotLight;
+
+
+/* The entire program's operation is contained within this structure. */
+typedef struct
+{
+       /* XWindows specific variables. */
+       Display *dpy;
+       Window Win;
+       Screen *screen;
+        Pixmap source;
+       GC GraphicsContext;
+       XColor *xColors;
+       unsigned long *aColors;
+       XImage *pXImage;
+       XShmSegmentInfo XShmInfo;
+
+       uint8_t nColorCount;                            /* Number of colors used. */
+       uint8_t bytesPerPixel;
+       uint16_t iWinWidth, iWinHeight;
+       uint16_t *aBumpMap;                             /* The actual bump map. */
+       SSpotLight SpotLight;
+
+        int delay;
+        int duration;
+        time_t start_time;
+
+        async_load_state *img_loader;
+} SBumps;
+
 
 static void SetPalette(Display *, SBumps *, XWindowAttributes * );
 static void InitBumpMap(Display *, SBumps *, XWindowAttributes * );
@@ -39,37 +138,37 @@ static void SoftenBumpMap( SBumps * );
 
 
 /* This function pointer will point to the appropriate PutPixel*() function below. */
-static void (*MyPutPixel)( int8_ *, uint32_ );
+static void (*MyPutPixel)( int8_t *, uint32_t );
 
-static void PutPixel32( int8_ *pData, uint32_ pixel )
+static void PutPixel32( int8_t *pData, uint32_t pixel )
 {
-       *(uint32_ *)pData = pixel;
+       *(uint32_t *)pData = pixel;
 }
 
-static void PutPixel24( int8_ *pData, uint32_ pixel )
+static void PutPixel24( int8_t *pData, uint32_t pixel )
 {
        pData[ 2 ] = ( pixel & 0x00FF0000 ) >> 16;
        pData[ 1 ] = ( pixel & 0x0000FF00 ) >> 8;
        pData[ 0 ] = ( pixel & 0x000000FF );
 }
 
-static void PutPixel16( int8_ *pData, uint32_ pixel )
+static void PutPixel16( int8_t *pData, uint32_t pixel )
 {
-       *(uint16_ *)pData = (uint16_)pixel;
+       *(uint16_t *)pData = (uint16_t)pixel;
 }
 
-static void PutPixel8( int8_ *pData, uint32_ pixel )
+static void PutPixel8( int8_t *pData, uint32_t pixel )
 {
-       *(uint8_ *)pData = (uint8_)pixel;
+       *(uint8_t *)pData = (uint8_t)pixel;
 }
 
 /* Creates the light map, which is a circular image... going from black around the edges
  * to white in the center. */
-static void CreateSpotLight( SSpotLight *pSpotLight, uint16_ iDiameter, uint16_ nColorCount )
+static void CreateSpotLight( SSpotLight *pSpotLight, uint16_t iDiameter, uint16_t nColorCount )
 {
        double nDist;
-       int16_ iDistX, iDistY;
-       uint8_ *pLOffset;
+       int16_t iDistX, iDistY;
+       uint8_t *pLOffset;
        
        pSpotLight->nFalloffDiameter = iDiameter;
        pSpotLight->nFalloffRadius = pSpotLight->nFalloffDiameter / 2;
@@ -80,7 +179,7 @@ static void CreateSpotLight( SSpotLight *pSpotLight, uint16_ iDiameter, uint16_
        printf( "%s: Spot Light Diameter: %d\n", progclass, pSpotLight->nLightDiameter );
 #endif
 
-       pSpotLight->aLightMap = malloc( pSpotLight->nLightDiameter * pSpotLight->nLightDiameter * sizeof(uint8_) );
+       pSpotLight->aLightMap = malloc( pSpotLight->nLightDiameter * pSpotLight->nLightDiameter * sizeof(uint8_t) );
 
        pLOffset = pSpotLight->aLightMap;
        for( iDistY=-pSpotLight->nLightRadius; iDistY<pSpotLight->nLightRadius; ++iDistY )
@@ -89,7 +188,7 @@ static void CreateSpotLight( SSpotLight *pSpotLight, uint16_ iDiameter, uint16_
                {
                        nDist = sqrt( pow( iDistX+0.5F, 2 ) + pow( iDistY+0.5F, 2 ) );
                        if( nDist / pSpotLight->nLightRadius <= 1.0f )
-                               *pLOffset = (uint8_)(nColorCount - ( ( nDist / pSpotLight->nLightRadius ) * ( nColorCount - 1 ) ));
+                               *pLOffset = (uint8_t)(nColorCount - ( ( nDist / pSpotLight->nLightRadius ) * ( nColorCount - 1 ) ));
                        else
                                *pLOffset = 0;
 
@@ -148,8 +247,8 @@ static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin )
 {
        XWindowAttributes XWinAttribs;
        XGCValues GCValues;
-       int32_ nGCFlags;
-       uint16_ iDiameter;
+       int32_t nGCFlags;
+       uint16_t iDiameter;
 
        /* Make size and velocity a function of window size, so it appears the same at 100x60 as it does in 3200x1200. */
        XGetWindowAttributes( dpy, NewWin, &XWinAttribs );
@@ -161,7 +260,7 @@ static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin )
        pBumps->SpotLight.nAccelMax = pBumps->SpotLight.nVelocityMax / 10.0f;
        pBumps->dpy = dpy;
        pBumps->Win = NewWin;
-       pBumps->pXImage = NULL;
+    pBumps->screen = XWinAttribs.screen;
        
        iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 2;
 
@@ -169,26 +268,8 @@ static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin )
        constraining it to be a multiple of 8 seems to fix it. */
     iDiameter = ((iDiameter+7)/8)*8;
 
-#ifdef HAVE_XSHM_EXTENSION
-       pBumps->bUseShm = get_boolean_resource(dpy,  "useSHM", "Boolean" );
-
-       if( pBumps->bUseShm )
-       {
-               pBumps->pXImage = create_xshm_image( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth,
-                                                                                        ZPixmap, NULL, &pBumps->XShmInfo, iDiameter, iDiameter );
-               if( !pBumps->pXImage )
-               {
-                       fprintf( stderr, "%s: Unable to create XShmImage.\n", progname );
-                       pBumps->bUseShm = False;
-               }
-       }
-#endif /* HAVE_XSHM_EXTENSION */
-       if( !pBumps->pXImage )
-       {
-               pBumps->pXImage = XCreateImage( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth, 
-                                                                       ZPixmap, 0, NULL, iDiameter, iDiameter, BitmapPad( pBumps->dpy ), 0 );
-               pBumps->pXImage->data = malloc( pBumps->pXImage->bytes_per_line * pBumps->pXImage->height * sizeof(int8_) );
-       }
+       pBumps->pXImage = create_xshm_image( pBumps->dpy, XWinAttribs.visual, XWinAttribs.depth,
+                                            ZPixmap, &pBumps->XShmInfo, iDiameter, iDiameter );
 
        /* For speed, access the XImage data directly using my own PutPixel routine. */
        switch( pBumps->pXImage->bits_per_pixel )
@@ -215,12 +296,7 @@ static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin )
 
                default:
                        fprintf( stderr, "%s: Unknown XImage depth.", progname );
-#ifdef HAVE_XSHM_EXTENSION
-                       if( pBumps->bUseShm )
-                               destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo );
-                       else
-#endif /* HAVE_XSHM_EXTENSION */
-                               XDestroyImage( pBumps->pXImage );
+                       destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo );
                        exit( 1 );
        }
        
@@ -243,7 +319,7 @@ static void SetPalette(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAtt
        XColor BaseColor;
        XColor Color;
        char *sColor;                   /* Spotlight Color */
-       int16_ iColor;
+       int16_t iColor;
        
        sColor = get_string_resource(dpy,  "color", "Color" );
 
@@ -270,7 +346,7 @@ static void SetPalette(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAtt
        if( pBumps->nColorCount < 2 )   pBumps->nColorCount = 2;
        if( pBumps->nColorCount > 128 ) pBumps->nColorCount = 128;
 
-       pBumps->aColors = malloc( pBumps->nColorCount * sizeof(uint32_ ) );
+       pBumps->aColors = malloc( pBumps->nColorCount * sizeof(unsigned long) );
 
        /* Creates a phong shade:                 / BaseColor  \                               Index/ColorCount 
         *                                                      PhongShade = | ------------ | Index + ( 65535 - BaseColor )^ 
@@ -278,15 +354,15 @@ static void SetPalette(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAtt
        pBumps->nColorCount--;
        for( iColor=0; iColor<=pBumps->nColorCount; iColor++ )
        {
-               Color.red   = (uint16_)( ( ( BaseColor.red   / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.red,   iColor/(double)pBumps->nColorCount ) );
-               Color.green = (uint16_)( ( ( BaseColor.green / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.green, iColor/(double)pBumps->nColorCount ) );
-               Color.blue  = (uint16_)( ( ( BaseColor.blue  / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.blue,  iColor/(double)pBumps->nColorCount ) );
+               Color.red   = (uint16_t)( ( ( BaseColor.red   / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.red,   iColor/(double)pBumps->nColorCount ) );
+               Color.green = (uint16_t)( ( ( BaseColor.green / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.green, iColor/(double)pBumps->nColorCount ) );
+               Color.blue  = (uint16_t)( ( ( BaseColor.blue  / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - BaseColor.blue,  iColor/(double)pBumps->nColorCount ) );
 
                if( !XAllocColor( pBumps->dpy, pXWinAttribs->colormap, &Color ) )
                {
                        XFreeColors( pBumps->dpy, pXWinAttribs->colormap, pBumps->aColors, iColor, 0 );
                        free( pBumps->aColors );
-                       pBumps->aColors = malloc( pBumps->nColorCount * sizeof(uint32_) );
+                       pBumps->aColors = malloc( pBumps->nColorCount * sizeof(unsigned long) );
                        pBumps->nColorCount--;
                        iColor = -1;
                }
@@ -320,27 +396,29 @@ static void InitBumpMap_2(Display *dpy, SBumps *pBumps)
 {
        XImage *pScreenImage;
        XColor *pColor;
-       uint8_ nSoften;
-       uint16_ iWidth, iHeight;
-       uint32_ nAverager;
-       uint16_ *pBump;
-       uint16_ maxHeight;
+       uint8_t nSoften;
+       uint16_t iWidth, iHeight;
+       uint32_t nAverager;
+       uint16_t        *pBump;
+       uint16_t maxHeight;
        double softenMultiplier = 1.0f;
        BOOL bInvert = (BOOL)get_boolean_resource(dpy,  "invert", "Boolean" );
     XWindowAttributes XWinAttribs;
     XGetWindowAttributes( pBumps->dpy, pBumps->Win, &XWinAttribs );
 
+    pBumps->start_time = time ((time_t *) 0);
+
        pScreenImage = XGetImage( pBumps->dpy, pBumps->source, 0, 0, 
                               pBumps->iWinWidth, pBumps->iWinHeight,
                               ~0L, ZPixmap );
-    XFreePixmap (pBumps->dpy, pBumps->source);
-    pBumps->source = 0;
+/*    XFreePixmap (pBumps->dpy, pBumps->source);
+    pBumps->source = 0;*/
 
        XSetWindowBackground( pBumps->dpy, pBumps->Win, pBumps->aColors[ 0 ] );
        XClearWindow (pBumps->dpy, pBumps->Win);
        XSync (pBumps->dpy, 0);
 
-       pBumps->aBumpMap = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_) );
+       pBumps->aBumpMap = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) );
        
        nSoften = get_integer_resource(dpy,  "soften", "Integer" );
        while( nSoften-- )
@@ -389,8 +467,8 @@ static void InitBumpMap_2(Display *dpy, SBumps *pBumps)
        while( nSoften-- )
                SoftenBumpMap( pBumps );
 
-       free( pBumps->xColors );
-    pBumps->xColors = 0;
+/*     free( pBumps->xColors );
+    pBumps->xColors = 0;*/
 }
 
 /* Soften the bump map.  This is to avoid pixelated-looking ridges.
@@ -404,10 +482,10 @@ static void InitBumpMap_2(Display *dpy, SBumps *pBumps)
  */
 static void SoftenBumpMap( SBumps *pBumps )
 {
-       uint16_ *pOffset, *pTOffset;
-       uint32_ nHeight;
-       uint32_ iWidth, iHeight;
-       uint16_ *aTempBuffer = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_) );
+       uint16_t *pOffset, *pTOffset;
+       uint32_t nHeight;
+       uint32_t iWidth, iHeight;
+       uint16_t *aTempBuffer = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) );
 
        pOffset = pBumps->aBumpMap;
        pTOffset = aTempBuffer;
@@ -433,7 +511,7 @@ static void SoftenBumpMap( SBumps *pBumps )
                }
        }                                               
 
-       memcpy( pBumps->aBumpMap, aTempBuffer, pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_) );
+       memcpy( pBumps->aBumpMap, aTempBuffer, pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_t) );
        free( aTempBuffer );
 }
 
@@ -441,14 +519,14 @@ static void SoftenBumpMap( SBumps *pBumps )
 /* This is where we slap down some pixels... */
 static void Execute( SBumps *pBumps )
 {
-       int32_ nLightXPos, nLightYPos;
-       int32_ iScreenX, iScreenY;
-       int32_ iLightX, iLightY;
-       uint16_ *pBOffset;
-       int8_ *pDOffset;
-       int32_ nX, nY;
-       uint16_ nColor;
-       int32_ nLightOffsetFar = pBumps->SpotLight.nFalloffDiameter - pBumps->SpotLight.nLightRadius;
+       int32_t nLightXPos, nLightYPos;
+       int32_t iScreenX, iScreenY;
+       int32_t iLightX, iLightY;
+       uint16_t *pBOffset;
+       int8_t *pDOffset;
+       int32_t nX, nY;
+       uint16_t nColor;
+       int32_t nLightOffsetFar = pBumps->SpotLight.nFalloffDiameter - pBumps->SpotLight.nLightRadius;
 
        CalcLightPos( pBumps );
        
@@ -463,7 +541,7 @@ static void Execute( SBumps *pBumps )
 
     /* warning: pointer targets in assignment differ in signedness
        Should pDOffset be a int8?  I can't tell.  -jwz, 22-Jul-2003 */
-               pDOffset = (int8_ *) &pBumps->pXImage->data[ (iLightY+pBumps->SpotLight.nLightRadius) * pBumps->pXImage->bytes_per_line ];
+               pDOffset = (int8_t *) &pBumps->pXImage->data[ (iLightY+pBumps->SpotLight.nLightRadius) * pBumps->pXImage->bytes_per_line ];
                pBOffset = pBumps->aBumpMap + ( iScreenY * pBumps->iWinWidth ) + nLightXPos;
                for( iScreenX=nLightXPos, iLightX=-pBumps->SpotLight.nLightRadius; iLightX<nLightOffsetFar; ++iScreenX, ++iLightX, ++pBOffset, pDOffset+=pBumps->bytesPerPixel )
                {
@@ -517,14 +595,8 @@ static void Execute( SBumps *pBumps )
                nY -= ( nLightYPos + nY ) - pBumps->iWinHeight;
        }
        
-#ifdef HAVE_XSHM_EXTENSION
-       if( pBumps->bUseShm )
-               XShmPutImage( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos,
-                                         nX, nY, False);
-       else
-#endif /* HAVE_XSHM_EXTENSION */
-               XPutImage( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos,
-                                  nX, nY );
+       put_xshm_image( pBumps->dpy, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos,
+                       nX, nY, &pBumps->XShmInfo);
 }
 
 
@@ -536,12 +608,7 @@ static void DestroyBumps( SBumps *pBumps )
        DestroySpotLight( &pBumps->SpotLight );
        free( pBumps->aColors );
        free( pBumps->aBumpMap );
-#ifdef HAVE_XSHM_EXTENSION
-       if( pBumps->bUseShm )
-               destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo );
-       else
-#endif /* HAVE_XSHM_EXTENSION */
-               XDestroyImage( pBumps->pXImage );
+       destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo );
 }
 
 
@@ -553,11 +620,15 @@ bumps_init (Display *dpy, Window Win)
 
 #ifdef VERBOSE
        time_t Time = time( NULL );
-       uint16_ iFrame = 0;
+       uint16_t iFrame = 0;
 #endif  /*  VERBOSE */
        
        CreateBumps( Bumps, dpy, Win );
        Bumps->delay = get_integer_resource(dpy,  "delay", "Integer" );
+    Bumps->duration = get_integer_resource (dpy, "duration", "Seconds");
+    if (Bumps->delay < 0) Bumps->delay = 0;
+    if (Bumps->duration < 1) Bumps->duration = 1;
+    Bumps->start_time = time ((time_t *) 0);
     return Bumps;
 }
 
@@ -574,7 +645,12 @@ bumps_draw (Display *dpy, Window window, void *closure)
       return Bumps->delay;
     }
 
-
+  if (!Bumps->img_loader &&
+      Bumps->start_time + Bumps->duration < time ((time_t *) 0)) {
+    Bumps->img_loader = load_image_async_simple (0, Bumps->screen,
+                                                 Bumps->Win, Bumps->source, 
+                                                 0, 0);
+  }
 
   Execute( Bumps );
 
@@ -600,6 +676,13 @@ bumps_reshape (Display *dpy, Window window, void *closure,
 static Bool
 bumps_event (Display *dpy, Window window, void *closure, XEvent *event)
 {
+  SBumps *Bumps = (SBumps *) closure;
+  if (screenhack_event_helper (dpy, window, event))
+    {
+      Bumps->start_time = 0;
+      return True;
+    }
+
   return False;
 }