X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fbumps.c;h=2f510f5a9b5a5b15487a21ddb4e457a5e953b223;hp=5eedaf7c107c23586c6728f77e545c5e080d5aa1;hb=07faf451b99879183ed7e909e43a0e065be1ee7f;hpb=93f25dc6827112d98b8b855ea85c8f5eb8123086 diff --git a/hacks/bumps.c b/hacks/bumps.c index 5eedaf7c..2f510f5a 100644 --- a/hacks/bumps.c +++ b/hacks/bumps.c @@ -1,4 +1,5 @@ -/* Bumps, Copyright (c) 1999 Shane Smit +/* -*- mode: C; tab-width: 4 -*- + * Bumps, Copyright (c) 2002, 2006 Shane Smit * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -8,7 +9,7 @@ * software for any purpose. It is provided "as is" without express or * implied warranty. * - * Module: "Bumps.cpp" + * Module: "bumps.c" * Tab Size: 4 * * Description: @@ -21,201 +22,276 @@ * 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 + * for code optimization. */ - #include "bumps.h" +static void SetPalette(Display *, SBumps *, XWindowAttributes * ); +static void InitBumpMap(Display *, SBumps *, XWindowAttributes * ); +static void InitBumpMap_2(Display *, SBumps *); +static void SoftenBumpMap( SBumps * ); -void CreateSpotLight( SSpotLight *pSpotLight, uint16_ iDiameter, uint16_ nColorCount ) -{ - double nDelta; - int16_ iHeight, iWidth; - - pSpotLight->nDiameter = iDiameter; -#ifdef VERBOSE - printf( "%s: Light Diameter: %d\n", progclass, pSpotLight->nDiameter ); -#endif - pSpotLight->aLightMap = calloc( pSpotLight->nDiameter * pSpotLight->nDiameter, sizeof(uint8_) ); - memset( pSpotLight->aLightMap, 0, pSpotLight->nDiameter * pSpotLight->nDiameter ); - /* The falloff max values... 3/4 of the entire lightmap. */ - pSpotLight->nRadius = (uint16_)(pSpotLight->nDiameter / 2.5F); - - for( iHeight=-pSpotLight->nRadius; iHeightnRadius; iHeight++ ) - for( iWidth=-pSpotLight->nRadius; iWidthnRadius; iWidth++ ) - { - nDelta = ( nColorCount * 2.5F ) - ( ( sqrt( pow( iWidth+0.5F, 2 ) + pow( iHeight+0.5F, 2 ) ) / pSpotLight->nRadius ) * ( nColorCount * 2.5F ) ); - nDelta += nColorCount; - if( nDelta >= ( nColorCount * 2 ) ) nDelta = ( nColorCount * 2 ) - 1; - if( nDelta >= nColorCount ) - pSpotLight->aLightMap[ ( ( iHeight + (pSpotLight->nDiameter/2) ) * pSpotLight->nDiameter ) + iWidth + (pSpotLight->nDiameter/2) ] = (uint8_)nDelta; - } - /* The actual lightmap... 1/2 of the entire lightmap. */ - pSpotLight->nRadius = pSpotLight->nDiameter / 4; +/* This function pointer will point to the appropriate PutPixel*() function below. */ +static void (*MyPutPixel)( int8_ *, uint32_ ); - for( iHeight=-pSpotLight->nRadius; iHeightnRadius; iHeight++ ) - for( iWidth=-pSpotLight->nRadius; iWidthnRadius; iWidth++ ) - { - nDelta = nColorCount - ( ( sqrt( pow( iWidth+0.5F, 2 ) + pow( iHeight+0.5F, 2 ) ) / pSpotLight->nRadius ) * ( nColorCount - 1 ) ); - if( nDelta >= 1 ) - pSpotLight->aLightMap[ ( ( iHeight + (pSpotLight->nDiameter/2) ) * pSpotLight->nDiameter ) + iWidth + (pSpotLight->nDiameter/2) ] = (uint8_)nDelta; - } - - CreateTables( pSpotLight ); +static void PutPixel32( int8_ *pData, uint32_ pixel ) +{ + *(uint32_ *)pData = pixel; +} + +static void PutPixel24( int8_ *pData, uint32_ pixel ) +{ + pData[ 2 ] = ( pixel & 0x00FF0000 ) >> 16; + pData[ 1 ] = ( pixel & 0x0000FF00 ) >> 8; + pData[ 0 ] = ( pixel & 0x000000FF ); +} - pSpotLight->nRadius = pSpotLight->nDiameter / 2; /* Now set the radius back to what it should be. */ - pSpotLight->nAngleX = RANDOM() % pSpotLight->nDegreeCount; - pSpotLight->nAngleY = RANDOM() % pSpotLight->nDegreeCount; - pSpotLight->nVelocityX = ( RANDOM() % 3 ) + 1; - pSpotLight->nVelocityY = ( RANDOM() % 3 ) + 1; +static void PutPixel16( int8_ *pData, uint32_ pixel ) +{ + *(uint16_ *)pData = (uint16_)pixel; } +static void PutPixel8( int8_ *pData, uint32_ pixel ) +{ + *(uint8_ *)pData = (uint8_)pixel; +} -void CreateTables( SSpotLight *pSpotLight ) +/* 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 ) { - double nUnit; - uint16_ iDegree; + double nDist; + int16_ iDistX, iDistY; + uint8_ *pLOffset; - pSpotLight->nDegreeCount = get_integer_resource( "degrees", "Integer" ); - if( pSpotLight->nDegreeCount < 180 ) pSpotLight->nDegreeCount = 180; /* Less than 180 will show trails in higher resolutions. */ + pSpotLight->nFalloffDiameter = iDiameter; + pSpotLight->nFalloffRadius = pSpotLight->nFalloffDiameter / 2; + pSpotLight->nLightDiameter = iDiameter / 2; + pSpotLight->nLightRadius = pSpotLight->nLightDiameter / 2; #ifdef VERBOSE - printf( "%s: Using a %d degree circle.\n", progclass, pSpotLight->nDegreeCount ); + printf( "%s: Falloff Diameter: %d\n", progclass, pSpotLight->nFalloffDiameter ); + printf( "%s: Spot Light Diameter: %d\n", progclass, pSpotLight->nLightDiameter ); #endif - pSpotLight->aSinTable = calloc( pSpotLight->nDegreeCount, sizeof(double) ); + pSpotLight->aLightMap = malloc( pSpotLight->nLightDiameter * pSpotLight->nLightDiameter * sizeof(uint8_) ); - /* This funtion builds the Sine Lookup Tables. */ - nUnit = (double)( PI * 2.0F ) / (double)( pSpotLight->nDegreeCount ); + pLOffset = pSpotLight->aLightMap; + for( iDistY=-pSpotLight->nLightRadius; iDistYnLightRadius; ++iDistY ) + { + for( iDistX=-pSpotLight->nLightRadius; iDistXnLightRadius; ++iDistX ) + { + 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 ) )); + else + *pLOffset = 0; - for( iDegree=0; iDegreenDegreeCount; iDegree++) - pSpotLight->aSinTable[ iDegree ] = sin( nUnit * (double)iDegree ); + ++pLOffset; + } + } + + /* Initialize movement variables. */ + pSpotLight->nAccelX = 0; + pSpotLight->nAccelY = 0; + pSpotLight->nVelocityX = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax; + pSpotLight->nVelocityY = ( RANDOM() % 2 ) ? pSpotLight->nVelocityMax : -pSpotLight->nVelocityMax; } -void CalcLightPos( SSpotLight *pSpotLight, uint16_ *pXPos, uint16_ *pYPos ) +/* Calculates the position of the spot light on the screen. */ +static void CalcLightPos( SBumps *pBumps ) { - pSpotLight->nVelocityX += ( RANDOM() % 2 ) ? 0.05F : -0.05F; - if( pSpotLight->nVelocityX < 1 ) pSpotLight->nVelocityX = 1; - else if( pSpotLight->nVelocityX > 3 ) pSpotLight->nVelocityX = 3; + SSpotLight *pSpotLight = &pBumps->SpotLight; + float nGravity; - pSpotLight->nVelocityX += ( RANDOM() % 2 ) ? 0.05F : -0.05F; - if( pSpotLight->nVelocityY < 1 ) pSpotLight->nVelocityX = 1; - else if( pSpotLight->nVelocityY > 3 ) pSpotLight->nVelocityX = 3; - - pSpotLight->nAngleX += pSpotLight->nVelocityX; - if( pSpotLight->nAngleX >= pSpotLight->nDegreeCount ) pSpotLight->nAngleX -= pSpotLight->nDegreeCount; + /* X */ + if( pSpotLight->nXPos < pSpotLight->nFalloffRadius ) nGravity = 1.0f; + else if( pSpotLight->nXPos > pBumps->iWinWidth - pSpotLight->nFalloffRadius ) nGravity = -1.0f; + else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f; + + pSpotLight->nAccelX += nGravity * ( pSpotLight->nAccelMax / 5.0f ); + if( pSpotLight->nAccelX < -pSpotLight->nAccelMax ) pSpotLight->nAccelX = -pSpotLight->nAccelMax; + else if( pSpotLight->nAccelX > pSpotLight->nAccelMax ) pSpotLight->nAccelX = pSpotLight->nAccelMax; - pSpotLight->nAngleY += pSpotLight->nVelocityY; - if( pSpotLight->nAngleY >= pSpotLight->nDegreeCount ) pSpotLight->nAngleY -= pSpotLight->nDegreeCount; + pSpotLight->nVelocityX += pSpotLight->nAccelX; + if( pSpotLight->nVelocityX < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = -pSpotLight->nVelocityMax; + else if( pSpotLight->nVelocityX > pSpotLight->nVelocityMax ) pSpotLight->nVelocityX = pSpotLight->nVelocityMax; - *pXPos = (uint16_)( ( pSpotLight->iWinXCenter - pSpotLight->nRadius ) * pSpotLight->aSinTable[ (uint16_)pSpotLight->nAngleX ] ) + pSpotLight->iWinXCenter; - *pYPos = (uint16_)( ( pSpotLight->iWinYCenter - pSpotLight->nRadius ) * pSpotLight->aSinTable[ (uint16_)pSpotLight->nAngleY ] ) + pSpotLight->iWinYCenter; + pSpotLight->nXPos += pSpotLight->nVelocityX; - /* Offset to upper left hand corner. */ - *pXPos -= pSpotLight->nRadius; - *pYPos -= pSpotLight->nRadius; + /* Y */ + if( pSpotLight->nYPos < pSpotLight->nFalloffRadius ) nGravity = 1.0f; + else if( pSpotLight->nYPos > pBumps->iWinHeight - pSpotLight->nFalloffRadius ) nGravity = -1.0f; + else nGravity = ( ( RANDOM() % 201 ) / 100.0f ) - 1.0f; + + pSpotLight->nAccelY += nGravity * ( pSpotLight->nAccelMax / 5.0f ); + if( pSpotLight->nAccelY < -pSpotLight->nAccelMax ) pSpotLight->nAccelY = -pSpotLight->nAccelMax; + else if( pSpotLight->nAccelY > pSpotLight->nAccelMax ) pSpotLight->nAccelY = pSpotLight->nAccelMax; + + pSpotLight->nVelocityY += pSpotLight->nAccelY; + if( pSpotLight->nVelocityY < -pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = -pSpotLight->nVelocityMax; + else if( pSpotLight->nVelocityY > pSpotLight->nVelocityMax ) pSpotLight->nVelocityY = pSpotLight->nVelocityMax; + + pSpotLight->nYPos += pSpotLight->nVelocityY; } -void CreateBumps( SBumps *pBumps, Display *pNewDisplay, Window NewWin ) +/* Main initialization function. */ +static void CreateBumps( SBumps *pBumps, Display *dpy, Window NewWin ) { XWindowAttributes XWinAttribs; XGCValues GCValues; int32_ nGCFlags; - uint16_ iWidth, iHeight; uint16_ iDiameter; - - XGetWindowAttributes( pNewDisplay, NewWin, &XWinAttribs ); + + /* 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 ); pBumps->iWinWidth = XWinAttribs.width; pBumps->iWinHeight = XWinAttribs.height; - pBumps->SpotLight.iWinXCenter = XWinAttribs.width / 2; - pBumps->SpotLight.iWinYCenter = XWinAttribs.height / 2; - pBumps->pDisplay = pNewDisplay; + pBumps->SpotLight.nXPos = XWinAttribs.width / 2.0f; + pBumps->SpotLight.nYPos = XWinAttribs.height / 2.0f; + pBumps->SpotLight.nVelocityMax = ( ( XWinAttribs.width < XWinAttribs.height ) ? XWinAttribs.width : XWinAttribs.height ) / 140.0f; + pBumps->SpotLight.nAccelMax = pBumps->SpotLight.nVelocityMax / 10.0f; + pBumps->dpy = dpy; pBumps->Win = NewWin; + pBumps->pXImage = NULL; + + iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 2; - pBumps->pXImage = XCreateImage( pBumps->pDisplay, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL, - pBumps->iWinWidth, pBumps->iWinHeight, BitmapPad( pBumps->pDisplay ), 0 ); - pBumps->pXImage->data = calloc( pBumps->pXImage->bytes_per_line * pBumps->pXImage->height, sizeof(int8_) ); + /* jwz: sometimes we get tearing if this lands on the wrong bounaary; + 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_) ); + } + + /* For speed, access the XImage data directly using my own PutPixel routine. */ + switch( pBumps->pXImage->bits_per_pixel ) + { + case 32: + pBumps->bytesPerPixel = 4; + MyPutPixel = PutPixel32; + break; + + case 24: + pBumps->bytesPerPixel = 3; + MyPutPixel = PutPixel24; + break; + + case 16: + pBumps->bytesPerPixel = 2; + MyPutPixel = PutPixel16; + break; + + case 8: + pBumps->bytesPerPixel = 1; + MyPutPixel = PutPixel8; + break; + + 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 ); + exit( 1 ); + } + GCValues.function = GXcopy; GCValues.subwindow_mode = IncludeInferiors; - nGCFlags = GCForeground | GCFunction; + nGCFlags = GCFunction; if( use_subwindow_mode_p( XWinAttribs.screen, pBumps->Win ) ) /* See grabscreen.c */ nGCFlags |= GCSubwindowMode; - pBumps->GraphicsContext = XCreateGC( pBumps->pDisplay, pBumps->Win, nGCFlags, &GCValues ); + pBumps->GraphicsContext = XCreateGC( pBumps->dpy, pBumps->Win, nGCFlags, &GCValues ); - SetPalette( pBumps, &XWinAttribs ); - iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 3; + SetPalette(dpy, pBumps, &XWinAttribs ); CreateSpotLight( &pBumps->SpotLight, iDiameter, pBumps->nColorCount ); - InitBumpMap( pBumps, &XWinAttribs ); - - /* Clear the image. */ - if (pBumps->aXColors[ 0 ].pixel == 0) - memset (pBumps->pXImage->data, 0, - pBumps->pXImage->bytes_per_line * pBumps->pXImage->height); - else - for( iHeight=0; iHeightiWinHeight; iHeight++ ) - for( iWidth=0; iWidthiWinWidth; iWidth++ ) - XPutPixel( pBumps->pXImage, iWidth, iHeight, - pBumps->aXColors[ 0 ].pixel ); - XSetWindowBackground( pBumps->pDisplay, pBumps->Win, - pBumps->aXColors[ 0 ].pixel ); - XClearWindow (pBumps->pDisplay, pBumps->Win); + InitBumpMap(dpy, pBumps, &XWinAttribs ); } -void SetPalette( SBumps *pBumps, XWindowAttributes *pXWinAttribs ) +/* Creates a specialized phong shade palette. */ +static void SetPalette(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAttribs ) { + XColor BaseColor; XColor Color; char *sColor; /* Spotlight Color */ int16_ iColor; - uint32_ *aPixels; - sColor = get_string_resource( "color", "Color" ); + sColor = get_string_resource(dpy, "color", "Color" ); - Color.red = RANDOM() % 0xFFFF; - Color.green = RANDOM() % 0xFFFF; - Color.blue = RANDOM() % 0xFFFF; + BaseColor.red = RANDOM() % 0xFFFF; + BaseColor.green = RANDOM() % 0xFFFF; + BaseColor.blue = RANDOM() % 0xFFFF; + + /* Make one color full intesity to avoid dark spotlights. */ + switch( RANDOM() % 3 ) + { + case 0: BaseColor.red = 0xFFFF; break; + case 1: BaseColor.green = 0xFFFF; break; + case 2: BaseColor.blue = 0xFFFF; break; + } - if( strcasecmp( sColor, "random" ) && !XParseColor( pBumps->pDisplay, pXWinAttribs->colormap, sColor, &Color ) ) + if( strcasecmp( sColor, "random" ) && !XParseColor( pBumps->dpy, pXWinAttribs->colormap, sColor, &BaseColor ) ) fprintf( stderr, "%s: color %s not found in database. Choosing random...\n", progname, sColor ); #ifdef VERBOSE - printf( "%s: Spotlight color is <%d,%d,%d> RGB.\n", progclass, Color.red, Color.green, Color.blue ); + printf( "%s: Spotlight color is <%d,%d,%d> RGB.\n", progclass, BaseColor.red, BaseColor.green, BaseColor.blue ); #endif /* VERBOSE */ - pBumps->nColorCount = get_integer_resource( "colorcount", "Integer" ); + pBumps->nColorCount = get_integer_resource(dpy, "colorcount", "Integer" ); if( pBumps->nColorCount < 2 ) pBumps->nColorCount = 2; if( pBumps->nColorCount > 128 ) pBumps->nColorCount = 128; - pBumps->aXColors = calloc( pBumps->nColorCount, sizeof(XColor ) ); - aPixels = calloc( pBumps->nColorCount, sizeof(uint32_) ); + pBumps->aColors = malloc( pBumps->nColorCount * sizeof(uint32_ ) ); - /* Creates a phong shade: / SpotColor \ Index/ColorCount - * PhongShade = | ------------ | Index + ( 65535 - SpotColor )^ + /* Creates a phong shade: / BaseColor \ Index/ColorCount + * PhongShade = | ------------ | Index + ( 65535 - BaseColor )^ * \ ColorCount / */ pBumps->nColorCount--; for( iColor=0; iColor<=pBumps->nColorCount; iColor++ ) { - pBumps->aXColors[ iColor ].red = (uint16_)( ( ( Color.red / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - Color.red, iColor/(double)pBumps->nColorCount ) ); - pBumps->aXColors[ iColor ].green = (uint16_)( ( ( Color.green / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - Color.green, iColor/(double)pBumps->nColorCount ) ); - pBumps->aXColors[ iColor ].blue = (uint16_)( ( ( Color.blue / (double)pBumps->nColorCount ) * iColor ) + pow( 0xFFFF - Color.blue, iColor/(double)pBumps->nColorCount ) ); + 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 ) ); - if( !XAllocColor( pBumps->pDisplay, pXWinAttribs->colormap, &pBumps->aXColors[ iColor ] ) ) + if( !XAllocColor( pBumps->dpy, pXWinAttribs->colormap, &Color ) ) { - XFreeColors( pBumps->pDisplay, pXWinAttribs->colormap, aPixels, iColor, 0 ); - free( pBumps->aXColors ); - free( aPixels ); + XFreeColors( pBumps->dpy, pXWinAttribs->colormap, pBumps->aColors, iColor, 0 ); + free( pBumps->aColors ); + pBumps->aColors = malloc( pBumps->nColorCount * sizeof(uint32_) ); pBumps->nColorCount--; - pBumps->aXColors = calloc( pBumps->nColorCount, sizeof(XColor) ); - aPixels = calloc( pBumps->nColorCount, sizeof(uint32_) ); iColor = -1; } else - aPixels[ iColor ] = pBumps->aXColors[ iColor ].pixel; + pBumps->aColors[ iColor ] = Color.pixel; } pBumps->nColorCount++; @@ -223,178 +299,319 @@ void SetPalette( SBumps *pBumps, XWindowAttributes *pXWinAttribs ) printf( "%s: Allocated %d colors.\n", progclass, pBumps->nColorCount ); #endif /* VERBOSE */ - XSetWindowBackground( pBumps->pDisplay, pBumps->Win, pBumps->aXColors[ 0 ].pixel ); + XSetWindowBackground( pBumps->dpy, pBumps->Win, pBumps->aColors[ 0 ] ); } -void InitBumpMap( SBumps *pBumps, XWindowAttributes *pXWinAttribs ) +/* Grabs the current contents of the window to use an intensity-based bump map. */ +static void InitBumpMap(Display *dpy, SBumps *pBumps, XWindowAttributes *pXWinAttribs ) +{ + pBumps->xColors = (XColor*)malloc( pBumps->iWinWidth * sizeof(XColor) ); + + if (pBumps->source) abort(); + pBumps->source = XCreatePixmap(pBumps->dpy, pBumps->Win, + pXWinAttribs->width, pXWinAttribs->height, + pXWinAttribs->depth); + pBumps->img_loader = load_image_async_simple (0, pXWinAttribs->screen, + pBumps->Win, pBumps->source, 0, 0); +} + +static void InitBumpMap_2(Display *dpy, SBumps *pBumps) { XImage *pScreenImage; - XColor *aColors; + XColor *pColor; uint8_ nSoften; uint16_ iWidth, iHeight; - BOOL bInvert = (BOOL)get_boolean_resource( "invert", "Boolean" ); + uint32_ nAverager; + uint16_ *pBump; + uint16_ maxHeight; + double softenMultiplier = 1.0f; + BOOL bInvert = (BOOL)get_boolean_resource(dpy, "invert", "Boolean" ); + XWindowAttributes XWinAttribs; + XGetWindowAttributes( pBumps->dpy, pBumps->Win, &XWinAttribs ); + + pScreenImage = XGetImage( pBumps->dpy, pBumps->source, 0, 0, + pBumps->iWinWidth, pBumps->iWinHeight, + ~0L, ZPixmap ); + 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_) ); - aColors = (XColor*)calloc( pBumps->iWinWidth, sizeof(XColor) ); - grab_screen_image( pXWinAttribs->screen, pBumps->Win ); - pScreenImage = XGetImage( pBumps->pDisplay, pBumps->Win, 0, 0, pBumps->iWinWidth, pBumps->iWinHeight, ~0L, ZPixmap ); + nSoften = get_integer_resource(dpy, "soften", "Integer" ); + while( nSoften-- ) + softenMultiplier *= 1.0f + ( 1.0f / 3.0f ); /* Softening takes the max height down, so scale up to compensate. */ + maxHeight = pBumps->SpotLight.nLightRadius * softenMultiplier; + nAverager = maxHeight ? ( 3 * 0xFFFF ) / maxHeight : 0; + + pBump = pBumps->aBumpMap; + if( bInvert ) /* Funny, it's actually the 'else' that inverts the bump map... */ + { + for( iHeight=0; iHeightiWinHeight; iHeight++ ) + { + pColor = pBumps->xColors; + for( iWidth=0; iWidthiWinWidth; iWidth++ ) + (pColor++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight ); - /* jwz: get the grabbed bits off the screen fast */ - XClearWindow (pBumps->pDisplay, pBumps->Win); - XSync (pBumps->pDisplay, 0); + XQueryColors( pBumps->dpy, XWinAttribs.colormap, pBumps->xColors, pBumps->iWinWidth ); - pBumps->aBumpMap = calloc( pBumps->iWinWidth * pBumps->iWinHeight, sizeof(uint16_) ); - for( iHeight=0; iHeightiWinHeight; iHeight++ ) + pColor = pBumps->xColors; + for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump ) + *pBump = ( nAverager ? ( pColor->red + pColor->green + pColor->blue ) / nAverager : 0 ); + } + } + else { - for( iWidth=0; iWidthiWinWidth; iWidth++ ) - aColors[ iWidth ].pixel = XGetPixel( pScreenImage, iWidth, iHeight ); + for( iHeight=0; iHeightiWinHeight; iHeight++ ) + { + pColor = pBumps->xColors; + for( iWidth=0; iWidthiWinWidth; iWidth++ ) + (pColor++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight ); - XQueryColors( pBumps->pDisplay, pXWinAttribs->colormap, aColors, pBumps->iWinWidth ); + XQueryColors( pBumps->dpy, XWinAttribs.colormap, pBumps->xColors, pBumps->iWinWidth ); - if( bInvert ) - for( iWidth=0; iWidthiWinWidth; iWidth++ ) - pBumps->aBumpMap[ ( iHeight * pBumps->iWinWidth ) + iWidth ] = (uint16_) - ( ( aColors[ iWidth ].red + aColors[ iWidth ].green + aColors[ iWidth ].blue ) / ( 0x2FFFD / (double)pBumps->SpotLight.nDiameter ) ); - else - for( iWidth=0; iWidthiWinWidth; iWidth++ ) - pBumps->aBumpMap[ ( iHeight * pBumps->iWinWidth ) + iWidth ] = (uint16_) - ( pBumps->SpotLight.nDiameter - ( ( aColors[ iWidth ].red + aColors[ iWidth ].green + aColors[ iWidth ].blue ) / ( 0x2FFFD / (double)pBumps->SpotLight.nDiameter ) ) ); + pColor = pBumps->xColors; + for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump ) + *pBump = ( maxHeight - ( nAverager ? ( pColor->red + pColor->green + pColor->blue ) / nAverager : 0 ) ); + } } XDestroyImage( pScreenImage ); - nSoften = get_integer_resource( "soften", "Integer" ); + nSoften = get_integer_resource(dpy, "soften", "Integer" ); #ifdef VERBOSE if( nSoften ) printf( "%s: Softening Bump Map %d time(s)...\n", progclass, nSoften ); #endif while( nSoften-- ) SoftenBumpMap( pBumps ); - free( aColors ); -} + free( pBumps->xColors ); + pBumps->xColors = 0; +} -void SoftenBumpMap( SBumps *pBumps ) +/* Soften the bump map. This is to avoid pixelated-looking ridges. + * |-----|-----|-----| + * | 0% |12.5%| 0% | The adjacent pixels are averaged together + * |-----|-----|-----| first. Then than value is averaged with + * |12.5%| 50% |12.5%| the pixel is question. This essentially weights + * |-----|-----|-----| each pixel as shown on the left. + * | 0% |12.5%| 0% | + * |-----|-----|-----| + */ +static void SoftenBumpMap( SBumps *pBumps ) { - uint16_ *pOffset; - uint16_ nHeight; - uint16_ iWidth, iHeight; - uint16_ *pTempBuffer = calloc( pBumps->iWinWidth * pBumps->iWinHeight, sizeof(uint16_) ); - - for( iHeight=1; iHeightiWinHeight-1; iHeight++ ) + uint16_ *pOffset, *pTOffset; + uint32_ nHeight; + uint32_ iWidth, iHeight; + uint16_ *aTempBuffer = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_) ); + + pOffset = pBumps->aBumpMap; + pTOffset = aTempBuffer; + for( iHeight=pBumps->iWinHeight; iHeight; --iHeight ) { - pOffset = pBumps->aBumpMap + ( iHeight * pBumps->iWinWidth ); - for( iWidth=1; iWidthiWinWidth-1; iWidth++ ) - { - nHeight = 0; - nHeight += pOffset[ iWidth ]; - nHeight += pOffset[ iWidth - pBumps->iWinWidth ]; - nHeight += pOffset[ iWidth + 1 ]; - nHeight += pOffset[ iWidth + pBumps->iWinWidth ]; - nHeight += pOffset[ iWidth - 1 ]; - nHeight /= 5; - pTempBuffer[ ( iHeight * pBumps->iWinWidth ) + iWidth ] = nHeight; + for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pOffset, ++pTOffset ) + { + if( iHeight==pBumps->iWinHeight || iHeight==1 || + iWidth==pBumps->iWinWidth || iWidth==1 ) + { + *pTOffset = 0; + continue; + } + + nHeight = pOffset[ -pBumps->iWinWidth ]; + nHeight += pOffset[ 1 ]; + nHeight += pOffset[ pBumps->iWinWidth ]; + nHeight += pOffset[ -1 ]; + nHeight >>= 2; + nHeight += pOffset[ 0 ]; + nHeight >>= 1; + *pTOffset = nHeight; } } - - memcpy( pBumps->aBumpMap, pTempBuffer, pBumps->iWinWidth * pBumps->iWinHeight * 2 ); - free( pTempBuffer ); + + memcpy( pBumps->aBumpMap, aTempBuffer, pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_) ); + free( aTempBuffer ); } -void Execute( SBumps *pBumps ) +/* This is where we slap down some pixels... */ +static void Execute( SBumps *pBumps ) { - uint16_ nLightXPos, nLightYPos; - uint16_ iWidth, iHeight; - uint16_ iLightWidth, iLightHeight; + int32_ nLightXPos, nLightYPos; + int32_ iScreenX, iScreenY; + int32_ iLightX, iLightY; uint16_ *pBOffset; - uint8_ *pLOffset; - int16_ nX, nY; + int8_ *pDOffset; + int32_ nX, nY; uint16_ nColor; - CalcLightPos( &pBumps->SpotLight, &nLightXPos, &nLightYPos ); + int32_ nLightOffsetFar = pBumps->SpotLight.nFalloffDiameter - pBumps->SpotLight.nLightRadius; - for( iHeight=nLightYPos, iLightHeight=0; iLightHeightSpotLight.nDiameter; iHeight++, iLightHeight++ ) + CalcLightPos( pBumps ); + + /* Offset to upper left hand corner. */ + nLightXPos = pBumps->SpotLight.nXPos - pBumps->SpotLight.nFalloffRadius; + nLightYPos = pBumps->SpotLight.nYPos - pBumps->SpotLight.nFalloffRadius; + + for( iScreenY=nLightYPos, iLightY=-pBumps->SpotLight.nLightRadius; iLightYaBumpMap + ( iHeight * pBumps->iWinWidth ); - pLOffset = pBumps->SpotLight.aLightMap + ( iLightHeight * pBumps->SpotLight.nDiameter ); - for( iWidth=nLightXPos, iLightWidth=0; iLightWidthSpotLight.nDiameter; iWidth++, iLightWidth++ ) + if( iScreenY < 0 ) continue; + else if( iScreenY >= pBumps->iWinHeight ) break; + + /* 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 ]; + pBOffset = pBumps->aBumpMap + ( iScreenY * pBumps->iWinWidth ) + nLightXPos; + for( iScreenX=nLightXPos, iLightX=-pBumps->SpotLight.nLightRadius; iLightXbytesPerPixel ) { - if( pLOffset[ iLightWidth ] ) - { - nX = pBOffset[ iWidth + 1 ] - pBOffset[ iWidth ] + iLightWidth; - nY = pBOffset[ iWidth + pBumps->iWinWidth ] - pBOffset[ iWidth ] + iLightHeight; - - if( nX < 0 ) nX = 0; - else if( nX >= pBumps->SpotLight.nDiameter ) nX = pBumps->SpotLight.nDiameter - 1; - - if( nY < 0 ) nY = 0; - else if( nY >= pBumps->SpotLight.nDiameter ) nY = pBumps->SpotLight.nDiameter - 1; - - nColor = pBumps->SpotLight.aLightMap[ ( nY * pBumps->SpotLight.nDiameter ) + nX ]; - if( nColor >= pBumps->nColorCount ) - nColor = 1; - - if( pLOffset[ iLightWidth ] >= pBumps->nColorCount ) - if( nColor > pLOffset[ iLightWidth ] - pBumps->nColorCount ) - nColor = pLOffset[ iLightWidth ] - pBumps->nColorCount; - - XPutPixel( pBumps->pXImage, iWidth, iHeight, pBumps->aXColors[ nColor ].pixel ); + if( iScreenX < 0 ) continue; + else if( iScreenX >= pBumps->iWinWidth ) break; + else if( iScreenY == 0 || iScreenY >= pBumps->iWinHeight-2 || + iScreenX == 0 || iScreenX >= pBumps->iWinWidth-2 ) + { + MyPutPixel( pDOffset, pBumps->aColors[ 0 ] ); + continue; } - else - XPutPixel( pBumps->pXImage, iWidth, iHeight, pBumps->aXColors[ 0 ].pixel ); + + /* That's right folks, all the magic of bump mapping occurs in these two lines. (kinda disappointing, isn't it?) */ + nX = ( pBOffset[ 1 ] - pBOffset[ 0 ] ) + iLightX; + nY = ( pBOffset[ pBumps->iWinWidth ] - pBOffset[ 0 ] ) + iLightY; + + if( nX<0 || nX>=pBumps->SpotLight.nLightDiameter + || nY<0 || nY>=pBumps->SpotLight.nLightDiameter ) + { + MyPutPixel( pDOffset, pBumps->aColors[ 0 ] ); + continue; + } + + nColor = pBumps->SpotLight.aLightMap[ ( nY * pBumps->SpotLight.nLightDiameter ) + nX ]; + MyPutPixel( pDOffset, pBumps->aColors[ nColor ] ); } } - XPutImage( pBumps->pDisplay, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, nLightXPos, nLightYPos, nLightXPos, nLightYPos, pBumps->SpotLight.nDiameter, pBumps->SpotLight.nDiameter ); - XSync( pBumps->pDisplay, False ); + /* Allow the spotlight to go *slightly* off the screen by clipping the XImage. */ + iLightX = iLightY = 0; /* Use these for XImages X and Y now. */ + nX = nY = pBumps->SpotLight.nFalloffDiameter; /* Use these for XImage width and height now. */ + if( nLightXPos < 0 ) + { + iLightX = -nLightXPos; + nX -= iLightX; + nLightXPos = 0; + } + else if( nLightXPos + nX >= pBumps->iWinWidth ) + { + nX -= ( nLightXPos + nX ) - pBumps->iWinWidth; + } + + if( nLightYPos < 0 ) + { + iLightY = -nLightYPos; + nY -= iLightY; + nLightYPos = 0; + } + else if( nLightYPos + nY >= pBumps->iWinHeight ) + { + 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 ); } -void DestroyBumps( SBumps *pBumps ) +static void DestroySpotLight( SSpotLight *pSpotLight ) { free( pSpotLight->aLightMap ); } + +/* Clean up */ +static void DestroyBumps( SBumps *pBumps ) { DestroySpotLight( &pBumps->SpotLight ); - free( pBumps->aXColors ); + free( pBumps->aColors ); free( pBumps->aBumpMap ); - XDestroyImage( pBumps->pXImage ); +#ifdef HAVE_XSHM_EXTENSION + if( pBumps->bUseShm ) + destroy_xshm_image( pBumps->dpy, pBumps->pXImage, &pBumps->XShmInfo ); + else +#endif /* HAVE_XSHM_EXTENSION */ + XDestroyImage( pBumps->pXImage ); } /* All messages to the screensaver are processed here. */ -void screenhack( Display *pDisplay, Window Win ) +static void * +bumps_init (Display *dpy, Window Win) { - SBumps Bumps; - uint32_ iDelay; + SBumps *Bumps = (SBumps *) calloc (1, sizeof(SBumps)); + #ifdef VERBOSE time_t Time = time( NULL ); uint16_ iFrame = 0; #endif /* VERBOSE */ - CreateBumps( &Bumps, pDisplay, Win ); - iDelay = get_integer_resource( "delay", "Integer" ); + CreateBumps( Bumps, dpy, Win ); + Bumps->delay = get_integer_resource(dpy, "delay", "Integer" ); + return Bumps; +} + +static unsigned long +bumps_draw (Display *dpy, Window window, void *closure) +{ + SBumps *Bumps = (SBumps *) closure; + + if (Bumps->img_loader) /* still loading */ + { + Bumps->img_loader = load_image_async_simple (Bumps->img_loader, 0, 0, 0, 0, 0); + if (! Bumps->img_loader) /* just finished */ + InitBumpMap_2(dpy, Bumps); + return Bumps->delay; + } + - while( 1 ) - { - screenhack_handle_events( pDisplay ); - Execute( &Bumps ); - usleep( iDelay ); + + Execute( Bumps ); #ifdef VERBOSE - iFrame++; - if( Time - time( NULL ) ) - { - printf( "FPS: %d\n", iFrame ); - Time = time( NULL ); - iFrame = 0; - } + iFrame++; + if( Time - time( NULL ) ) + { + printf( "FPS: %d\n", iFrame ); + Time = time( NULL ); + iFrame = 0; + } #endif /* VERBOSE */ - } - DestroyBumps( &Bumps ); + return Bumps->delay; } - -/* - * End of Module: "Bumps.cpp" - */ +static void +bumps_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +bumps_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +bumps_free (Display *dpy, Window window, void *closure) +{ + SBumps *Bumps = (SBumps *) closure; + DestroyBumps( Bumps ); +} + + +XSCREENSAVER_MODULE ("Bumps", bumps) /* vim: ts=4 */