-/* Bumps, Copyright (c) 1999 Shane Smit <blackend@inconnect.com>
+/* -*- mode: C; tab-width: 4 -*-
+ * Bumps, Copyright (c) 2002 Shane Smit <CodeWeaver@DigitalLoom.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* software for any purpose. It is provided "as is" without express or
* implied warranty.
*
- * Module: "Bumps.cpp"
+ * Module: "bumps.c"
* Tab Size: 4
*
* Description:
* 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.
*/
-
#include "bumps.h"
+/* This function pointer will point to the appropriate PutPixel*() function below. */
+void (*MyPutPixel)( int8_ *, uint32_ );
-void CreateSpotLight( SSpotLight *pSpotLight, uint16_ iDiameter, uint16_ nColorCount )
+void PutPixel32( int8_ *pData, uint32_ pixel )
{
- 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; iHeight<pSpotLight->nRadius; iHeight++ )
- for( iWidth=-pSpotLight->nRadius; iWidth<pSpotLight->nRadius; 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;
+ *(uint32_ *)pData = pixel;
+}
- for( iHeight=-pSpotLight->nRadius; iHeight<pSpotLight->nRadius; iHeight++ )
- for( iWidth=-pSpotLight->nRadius; iWidth<pSpotLight->nRadius; 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 );
+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;
+void PutPixel16( int8_ *pData, uint32_ pixel )
+{
+ *(uint16_ *)pData = (uint16_)pixel;
}
+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. */
+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; iDistY<pSpotLight->nLightRadius; ++iDistY )
+ {
+ for( iDistX=-pSpotLight->nLightRadius; iDistX<pSpotLight->nLightRadius; ++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; iDegree<pSpotLight->nDegreeCount; 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. */
+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;
}
+/* Main initialization function. */
void CreateBumps( SBumps *pBumps, Display *pNewDisplay, Window NewWin )
{
XWindowAttributes XWinAttribs;
XGCValues GCValues;
int32_ nGCFlags;
- uint16_ iWidth, iHeight;
uint16_ iDiameter;
-
+
+ /* Make size and velocity a function of window size, so it appears the same at 100x60 as it does in 3200x1200. */
XGetWindowAttributes( pNewDisplay, NewWin, &XWinAttribs );
pBumps->iWinWidth = XWinAttribs.width;
pBumps->iWinHeight = XWinAttribs.height;
- pBumps->SpotLight.iWinXCenter = XWinAttribs.width / 2;
- pBumps->SpotLight.iWinYCenter = XWinAttribs.height / 2;
+ 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->pDisplay = pNewDisplay;
pBumps->Win = NewWin;
+ pBumps->pXImage = NULL;
+
+ iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 2;
+
+#ifdef HAVE_XSHM_EXTENSION
+ pBumps->bUseShm = get_boolean_resource( "useSHM", "Boolean" );
- 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_) );
+ if( pBumps->bUseShm )
+ {
+ pBumps->pXImage = create_xshm_image( pBumps->pDisplay, 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->pDisplay, XWinAttribs.visual, XWinAttribs.depth,
+ ZPixmap, 0, NULL, iDiameter, iDiameter, BitmapPad( pBumps->pDisplay ), 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->pDisplay, pBumps->pXImage, &pBumps->XShmInfo );
+ else
+#endif /* HAVE_XSHM_EXTENSION */
+ XDestroyImage( pBumps->pXImage );
+ exit( 1 );
+ }
+
GCValues.function = GXcopy;
GCValues.subwindow_mode = IncludeInferiors;
nGCFlags = GCForeground | GCFunction;
pBumps->GraphicsContext = XCreateGC( pBumps->pDisplay, pBumps->Win, nGCFlags, &GCValues );
SetPalette( pBumps, &XWinAttribs );
- iDiameter = ( ( pBumps->iWinWidth < pBumps->iWinHeight ) ? pBumps->iWinWidth : pBumps->iWinHeight ) / 3;
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; iHeight<pBumps->iWinHeight; iHeight++ )
- for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
- XPutPixel( pBumps->pXImage, iWidth, iHeight,
- pBumps->aXColors[ 0 ].pixel );
- XSetWindowBackground( pBumps->pDisplay, pBumps->Win,
- pBumps->aXColors[ 0 ].pixel );
- XClearWindow (pBumps->pDisplay, pBumps->Win);
+ XSetWindowBackground( pBumps->pDisplay, pBumps->Win, pBumps->aColors[ 0 ] );
+ XClearWindow (pBumps->pDisplay, pBumps->Win);
}
+/* Creates a specialized phong shade palette. */
void SetPalette( SBumps *pBumps, XWindowAttributes *pXWinAttribs )
{
+ XColor BaseColor;
XColor Color;
char *sColor; /* Spotlight Color */
int16_ iColor;
- uint32_ *aPixels;
sColor = get_string_resource( "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->pDisplay, 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" );
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->pDisplay, pXWinAttribs->colormap, &Color ) )
{
- XFreeColors( pBumps->pDisplay, pXWinAttribs->colormap, aPixels, iColor, 0 );
- free( pBumps->aXColors );
- free( aPixels );
+ XFreeColors( pBumps->pDisplay, 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++;
printf( "%s: Allocated %d colors.\n", progclass, pBumps->nColorCount );
#endif /* VERBOSE */
- XSetWindowBackground( pBumps->pDisplay, pBumps->Win, pBumps->aXColors[ 0 ].pixel );
+ XSetWindowBackground( pBumps->pDisplay, pBumps->Win, pBumps->aColors[ 0 ] );
}
+/* Grabs the current contents of the window to use an intensity-based bump map. */
void InitBumpMap( SBumps *pBumps, XWindowAttributes *pXWinAttribs )
{
XImage *pScreenImage;
- XColor *aColors;
+ XColor *aColors, *pColor;
uint8_ nSoften;
uint16_ iWidth, iHeight;
+ uint32_ nAverager;
+ uint16_ *pBump;
+ uint16_ maxHeight;
+ double softenMultiplier = 1.0f;
BOOL bInvert = (BOOL)get_boolean_resource( "invert", "Boolean" );
-
- 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 );
+ Pixmap p;
- /* jwz: get the grabbed bits off the screen fast */
- XClearWindow (pBumps->pDisplay, pBumps->Win);
- XSync (pBumps->pDisplay, 0);
+ aColors = (XColor*)malloc( pBumps->iWinWidth * sizeof(XColor) );
- pBumps->aBumpMap = calloc( pBumps->iWinWidth * pBumps->iWinHeight, sizeof(uint16_) );
- for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
- {
- for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
- aColors[ iWidth ].pixel = XGetPixel( pScreenImage, iWidth, iHeight );
+ p = XCreatePixmap(pBumps->pDisplay, pBumps->Win,
+ pXWinAttribs->width, pXWinAttribs->height,
+ pXWinAttribs->depth);
+ load_random_image (pXWinAttribs->screen, pBumps->Win, p);
+
+ pScreenImage = XGetImage( pBumps->pDisplay, p, 0, 0, pBumps->iWinWidth, pBumps->iWinHeight, ~0L, ZPixmap );
+ XFreePixmap (pBumps->pDisplay, p);
+
+ /* jwz: get the grabbed bits off the screen fast */
+ XClearWindow (pBumps->pDisplay, pBumps->Win);
+ XSync (pBumps->pDisplay, 0);
- XQueryColors( pBumps->pDisplay, pXWinAttribs->colormap, aColors, pBumps->iWinWidth );
+ pBumps->aBumpMap = malloc( pBumps->iWinWidth * pBumps->iWinHeight * sizeof(uint16_) );
- if( bInvert )
+ nSoften = get_integer_resource( "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 = ( 3 * 0xFFFF ) / maxHeight;
+
+ pBump = pBumps->aBumpMap;
+ if( bInvert ) /* Funny, it's actually the 'else' that inverts the bump map... */
+ {
+ for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
+ {
+ pColor = aColors;
for( iWidth=0; iWidth<pBumps->iWinWidth; iWidth++ )
- pBumps->aBumpMap[ ( iHeight * pBumps->iWinWidth ) + iWidth ] = (uint16_)
- ( ( aColors[ iWidth ].red + aColors[ iWidth ].green + aColors[ iWidth ].blue ) / ( 0x2FFFD / (double)pBumps->SpotLight.nDiameter ) );
- else
+ (pColor++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight );
+
+ XQueryColors( pBumps->pDisplay, pXWinAttribs->colormap, aColors, pBumps->iWinWidth );
+
+ pColor = aColors;
+ for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump )
+ *pBump = ( ( pColor->red + pColor->green + pColor->blue ) / nAverager );
+ }
+ }
+ else
+ {
+ for( iHeight=0; iHeight<pBumps->iWinHeight; iHeight++ )
+ {
+ pColor = aColors;
for( iWidth=0; iWidth<pBumps->iWinWidth; 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++)->pixel = XGetPixel( pScreenImage, iWidth, iHeight );
+
+ XQueryColors( pBumps->pDisplay, pXWinAttribs->colormap, aColors, pBumps->iWinWidth );
+
+ pColor = aColors;
+ for( iWidth=pBumps->iWinWidth; iWidth; --iWidth, ++pColor, ++pBump )
+ *pBump = ( maxHeight - ( ( pColor->red + pColor->green + pColor->blue ) / nAverager ) );
+ }
}
XDestroyImage( pScreenImage );
#endif
while( nSoften-- )
SoftenBumpMap( pBumps );
+
free( aColors );
}
-
+/* Soften the bump map. This is to avoid pixellated-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% |
+ * |-----|-----|-----|
+ */
void SoftenBumpMap( SBumps *pBumps )
{
- uint16_ *pOffset;
- uint16_ nHeight;
- uint16_ iWidth, iHeight;
- uint16_ *pTempBuffer = calloc( pBumps->iWinWidth * pBumps->iWinHeight, sizeof(uint16_) );
-
- for( iHeight=1; iHeight<pBumps->iWinHeight-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; iWidth<pBumps->iWinWidth-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 );
}
+/* This is where we slap down some pixels... */
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; iLightHeight<pBumps->SpotLight.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; iLightY<nLightOffsetFar; ++iScreenY, ++iLightY )
{
- pBOffset = pBumps->aBumpMap + ( iHeight * pBumps->iWinWidth );
- pLOffset = pBumps->SpotLight.aLightMap + ( iLightHeight * pBumps->SpotLight.nDiameter );
- for( iWidth=nLightXPos, iLightWidth=0; iLightWidth<pBumps->SpotLight.nDiameter; iWidth++, iLightWidth++ )
+ if( iScreenY < 0 ) continue;
+ else if( iScreenY >= pBumps->iWinHeight ) break;
+
+ pDOffset = &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 )
{
- 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 );
+ /* 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->pDisplay, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos,
+ nX, nY, False);
+ else
+#endif /* HAVE_XSHM_EXTENSION */
+ XPutImage( pBumps->pDisplay, pBumps->Win, pBumps->GraphicsContext, pBumps->pXImage, iLightX, iLightY, nLightXPos, nLightYPos,
+ nX, nY );
+
XSync( pBumps->pDisplay, False );
}
+/* Clean up */
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->pDisplay, pBumps->pXImage, &pBumps->XShmInfo );
+ else
+#endif /* HAVE_XSHM_EXTENSION */
+ XDestroyImage( pBumps->pXImage );
}
}
-/*
- * End of Module: "Bumps.cpp"
- */
-
/* vim: ts=4
*/