summaryrefslogtreecommitdiffstats
path: root/hacks/eruption.c
diff options
context:
space:
mode:
authorSimon Rettberg2020-12-02 08:23:52 +0100
committerSimon Rettberg2020-12-02 08:23:52 +0100
commit2954208d00d422b34fa3a69631b0a091f17a349d (patch)
treeb4322e320155656af133b8f47025d00b17a68f64 /hacks/eruption.c
parentUpdate to 5.43 (diff)
downloadxscreensaver-2954208d00d422b34fa3a69631b0a091f17a349d.tar.gz
xscreensaver-2954208d00d422b34fa3a69631b0a091f17a349d.tar.xz
xscreensaver-2954208d00d422b34fa3a69631b0a091f17a349d.zip
5.44
Diffstat (limited to 'hacks/eruption.c')
-rw-r--r--hacks/eruption.c330
1 files changed, 205 insertions, 125 deletions
diff --git a/hacks/eruption.c b/hacks/eruption.c
index 3f68cf7..a4cfc25 100644
--- a/hacks/eruption.c
+++ b/hacks/eruption.c
@@ -10,13 +10,24 @@
*
* Module - "eruption.c"
*
+ * [01-2015] - Dave Odell <dmo2118@gmail.com>: Performance tweaks. Also, click-for-explosion.
* [02-2003] - W.P. van Paassen: Improvements, added some code of jwz from the pyro hack for a spherical distribution of the particles
* [01-2003] - W.P. van Paassen: Port to X for use with XScreenSaver, the shadebob hack by Shane Smit was used as a template
* [04-2002] - W.P. van Paassen: Creation for the Demo Effects Collection (http://demo-effects.sourceforge.net)
*/
+#include <assert.h>
#include <math.h>
#include "screenhack.h"
+#include "xshm.h"
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#else
+typedef unsigned long uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+#endif
/*#define VERBOSE*/
@@ -42,7 +53,7 @@ struct state {
PARTICLE *particles;
unsigned short iWinWidth, iWinHeight;
- unsigned char **fire;
+ unsigned char *fire;
unsigned short nParticleCount;
unsigned char xdelta, ydelta, decay;
signed char gravity;
@@ -53,6 +64,7 @@ struct state {
signed short iColorCount;
unsigned long *aiColorVals;
XImage *pImage;
+ XShmSegmentInfo shm_info;
int draw_i;
};
@@ -85,12 +97,18 @@ static void init_particle(struct state *st, PARTICLE* particle, unsigned short x
particle->dead = 0;
}
+#define X_PAD 1 /* Could be more if anybody wants the blur to fall off the left/right edges. */
+#define Y_PAD 1
+
+
static void Execute( struct state *st )
{
+ XImage *img = st->pImage;
int i, j;
- unsigned int temp;
+ size_t fire_pitch = st->iWinWidth + X_PAD * 2;
+ unsigned char *line0, *line1, *line2;
- /* move and draw particles into st->fire array */
+ /* move particles */
for (i = 0; i < st->nParticleCount; i++)
{
@@ -141,74 +159,123 @@ static void Execute( struct state *st )
/* particle cools off */
st->particles[i].colorindex--;
-
- /* draw particle */
- if (st->iWinHeight <= 2 || st->iWinWidth <= 2) continue;
- st->fire[st->particles[i].ypos][st->particles[i].xpos] = st->particles[i].colorindex;
- st->fire[st->particles[i].ypos][st->particles[i].xpos - 1] = st->particles[i].colorindex;
- st->fire[st->particles[i].ypos + 1][st->particles[i].xpos] = st->particles[i].colorindex;
- st->fire[st->particles[i].ypos - 1][st->particles[i].xpos] = st->particles[i].colorindex;
- st->fire[st->particles[i].ypos][st->particles[i].xpos + 1] = st->particles[i].colorindex;
}
}
-
- /* create st->fire effect */
- for (i = 0; i < st->iWinHeight; i++)
+
+ /* draw particles into st->fire array */
+ for( i = 0; i < st->nParticleCount; i++ )
{
- for (j = 0; j < st->iWinWidth; j++)
- {
- if (j + 1 >= st->iWinWidth)
- temp = 0;
- else
- temp = st->fire[i][j + 1];
+ PARTICLE *p = &st->particles[i];
+ if( !p->dead && p->ypos >= -Y_PAD + 1 && p->ypos < st->iWinHeight + Y_PAD - 1 )
+ {
+ /* draw particle */
+ unsigned char *center = st->fire + (p->ypos - -Y_PAD) * fire_pitch + (p->xpos + X_PAD);
+ unsigned char color = p->colorindex;
+ *center = color;
+ center[-1] = color;
+ if (p->ypos < st->iWinHeight + Y_PAD - 2)
+ center[fire_pitch] = color;
+ if (p->ypos >= -Y_PAD + 2)
+ center[-fire_pitch] = color;
+ center[1] = color;
+ }
+ }
- if (j - 1 >= 0)
- temp += st->fire[i][j - 1];
+ line0 = st->fire + X_PAD;
+ line1 = line0 + fire_pitch;
+ line2 = line1 + fire_pitch;
- if (i - 1 >= 0)
- {
- temp += st->fire[i - 1][j];
- if (j - 1 >= 0)
- temp += st->fire[i - 1][j - 1];
- if (j + 1 < st->iWinWidth)
- temp += st->fire[i - 1][j + 1];
- }
-
- if (i + 1 < st->iWinHeight)
- {
- temp += st->fire[i + 1][j];
- if (j + 1 < st->iWinWidth)
- temp += st->fire[i + 1][j + 1];
- if (j - 1 >= 0)
- temp += st->fire[i + 1][j - 1];
- }
-
- temp >>= 3;
-
- if (temp > st->decay)
- {
- temp -= st->decay;
- }
- else
- temp = 0;
-
- st->fire[i][j] = temp;
- }
+ /* create st->fire effect */
+
+ switch( img->bits_per_pixel )
+ {
+ case 8:
+ case 16:
+ case 32:
+ break;
+ default:
+ memset( img->data, 0, img->bytes_per_line * img->height );
+ break;
}
-
- memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height );
-
- /* draw st->fire array to screen */
- for (i = 0; i < st->iWinHeight; ++i)
+
+ for( i = -Y_PAD + 1; i < st->iWinHeight + Y_PAD - 1; i++ )
{
- for (j = 0; j < st->iWinWidth; ++j)
- {
- if (st->fire[i][j] > 0)
- XPutPixel( st->pImage, j, i, st->aiColorVals[ st->fire[i][j] ] );
- }
+ const int j0 = -X_PAD + 1;
+
+ unsigned
+ t0 = line0[j0 - 1] + line1[j0 - 1] + line2[j0 - 1],
+ t1 = line0[j0] + line1[j0] + line2[j0];
+
+ unsigned j1 = st->iWinWidth + X_PAD;
+
+ /* This is basically like the GIMP's "Convolution Matrix" filter, with
+ the following settings:
+ Matrix:
+ | 1 1 1 | Divisor = 8
+ | 1 0 1 | Offset = -eruption.cooloff
+ | 1 1 1 |
+ Except that the effect is applied to each pixel individually, in order
+ from left-to-right, then top-to-bottom, resulting in a slight smear
+ going rightwards and downwards.
+ */
+
+ for( j = j0 + 1; j != j1; j++ )
+ {
+ unsigned t2 = line0[j] + line1[j] + line2[j];
+ unsigned char *px = line1 + j - 1;
+ int temp;
+ t1 -= *px;
+ temp = t0 + t1 + t2 - st->decay;
+ temp = temp >= 0 ? temp >> 3 : 0;
+ *px = temp;
+ t0 = t1 + temp;
+ t1 = t2;
+ }
+
+ if( i >= 0 && i < st->iWinHeight )
+ {
+ /* draw st->fire array to screen */
+ void *out_ptr = img->data + img->bytes_per_line * i;
+
+ switch( img->bits_per_pixel )
+ {
+ case 32:
+ {
+ uint32_t *out = (uint32_t *)out_ptr;
+ for( j = 0; j < st->iWinWidth; ++j )
+ out[j] = st->aiColorVals[ line1[j] ];
+ }
+ break;
+ case 16:
+ {
+ uint16_t *out = (uint16_t *)out_ptr;
+ for( j = 0; j < st->iWinWidth; ++j )
+ out[j] = st->aiColorVals[ line1[j] ];
+ }
+ break;
+ case 8:
+ {
+ uint8_t *out = (uint8_t *)out_ptr;
+ for( j = 0; j < st->iWinWidth; ++j )
+ out[j] = st->aiColorVals[ line1[j] ];
+ }
+ break;
+ default:
+ for( j = 0; j < st->iWinWidth; ++j )
+ {
+ if( line1[j] )
+ XPutPixel( img, j, i, st->aiColorVals[ line1[j] ] );
+ }
+ break;
+ }
+ }
+
+ line0 += fire_pitch;
+ line1 += fire_pitch;
+ line2 += fire_pitch;
}
- XPutImage( st->dpy, st->window, st->gc, st->pImage,
- 0,0,0,0, st->iWinWidth, st->iWinHeight );
+ put_xshm_image( st->dpy, st->window, st->gc, st->pImage,
+ 0,0,0,0, st->iWinWidth, st->iWinHeight, &st->shm_info );
}
static unsigned long * SetPalette(struct state *st)
@@ -294,43 +361,41 @@ static unsigned long * SetPalette(struct state *st)
}
-static void Initialize( struct state *st )
+static void DestroyImage (struct state *st)
{
- XGCValues gcValues;
- XWindowAttributes XWinAttribs;
- int /*iBitsPerPixel,*/ i;
+ free (st->fire);
+ destroy_xshm_image (st->dpy, st->pImage, &st->shm_info);
+}
- /* Create the Image for drawing */
- XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
+static void CreateImage( struct state *st, XWindowAttributes *XWinAttribs )
+{
+ /* Create the Image for drawing */
- /* Find the preferred bits-per-pixel. (jwz) */
- {
- int pfvc = 0;
- XPixmapFormatValues *pfv = XListPixmapFormats( st->dpy, &pfvc );
- for( i=0; i<pfvc; i++ )
- if( pfv[ i ].depth == XWinAttribs.depth )
- {
- /*iBitsPerPixel = pfv[ i ].bits_per_pixel;*/
- break;
- }
- if( pfv )
- XFree (pfv);
- }
+ /* Must be NULL because of how DestroyImage works. */
+ assert( !st->fire );
- /* Create the GC. */
- st->gc = XCreateGC( st->dpy, st->window, 0, &gcValues );
+ st->pImage = create_xshm_image( st->dpy, XWinAttribs->visual,
+ XWinAttribs->depth, ZPixmap, &st->shm_info,
+ XWinAttribs->width, XWinAttribs->height );
+
+ memset( (st->pImage)->data, 0,
+ (st->pImage)->bytes_per_line * (st->pImage)->height);
- st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
- XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 );
- (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height);
+ st->iWinWidth = XWinAttribs->width;
+ st->iWinHeight = XWinAttribs->height;
+
+ /* create st->fire array */
+ st->fire = calloc( (st->iWinHeight + Y_PAD * 2) * (st->iWinWidth + X_PAD * 2), sizeof(unsigned char));
+}
- st->iWinWidth = XWinAttribs.width;
- st->iWinHeight = XWinAttribs.height;
+static void Initialize( struct state *st, XWindowAttributes *XWinAttribs )
+{
+ XGCValues gcValues;
+
+ /* Create the GC. */
+ st->gc = XCreateGC( st->dpy, st->window, 0, &gcValues );
- /* create st->fire array */
- st->fire = calloc( st->iWinHeight, sizeof(unsigned char*));
- for (i = 0; i < st->iWinHeight; ++i)
- st->fire[i] = calloc( st->iWinWidth, sizeof(unsigned char));
+ CreateImage (st, XWinAttribs);
/*create st->particles */
st->particles = malloc (st->nParticleCount * sizeof(PARTICLE));
@@ -361,6 +426,7 @@ eruption_init (Display *dpy, Window window)
st->decay = 0;
if (st->decay > 10)
st->decay = 10;
+ st->decay <<= 3;
st->gravity = get_integer_resource(st->dpy, "gravity", "Integer" );
if (st->gravity < -5)
@@ -378,7 +444,9 @@ eruption_init (Display *dpy, Window window)
printf( "%s: Allocated %d st->particles\n", progclass, st->nParticleCount );
#endif /* VERBOSE */
- Initialize( st );
+ XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
+
+ Initialize( st, &XWinAttribs );
st->ydelta = 0;
while (sum < (st->iWinHeight >> 1) - SPREAD)
@@ -399,12 +467,10 @@ eruption_init (Display *dpy, Window window)
cache(st);
- XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
XFreeColors( st->dpy, XWinAttribs.colormap, st->aiColorVals, st->iColorCount, 0 );
free( st->aiColorVals );
st->aiColorVals = SetPalette( st );
XClearWindow( st->dpy, st->window );
- memset( st->pImage->data, 0, st->pImage->bytes_per_line * st->pImage->height );
st->draw_i = -1;
@@ -412,6 +478,23 @@ eruption_init (Display *dpy, Window window)
}
+static void
+new_eruption (struct state *st, unsigned short xcenter, unsigned short ycenter)
+{
+ for (st->draw_i = 0; st->draw_i < st->nParticleCount; st->draw_i++)
+ init_particle(st, st->particles + st->draw_i, xcenter, ycenter);
+ st->draw_i = 0;
+}
+
+
+static void
+random_eruption (struct state *st)
+{
+ /* compute random center */
+ new_eruption (st, random() % st->iWinWidth, random() % st->iWinHeight);
+}
+
+
static unsigned long
eruption_draw (Display *dpy, Window window, void *closure)
{
@@ -419,14 +502,7 @@ eruption_draw (Display *dpy, Window window, void *closure)
if( st->draw_i < 0 || st->draw_i++ >= st->cycles )
{
- /* compute random center */
- unsigned short xcenter, ycenter;
- xcenter = random() % st->iWinWidth;
- ycenter = random() % st->iWinHeight;
-
- for (st->draw_i = 0; st->draw_i < st->nParticleCount; st->draw_i++)
- init_particle(st, st->particles + st->draw_i, xcenter, ycenter);
- st->draw_i = 0;
+ random_eruption (st);
}
Execute( st );
@@ -451,31 +527,33 @@ eruption_reshape (Display *dpy, Window window, void *closure,
{
struct state *st = (struct state *) closure;
XWindowAttributes XWinAttribs;
- int i;
- for (i = 0; i < st->iWinHeight; ++i)
- free (st->fire[i]);
+ DestroyImage (st);
+ st->fire = NULL;
- st->iWinWidth = w;
- st->iWinHeight = h;
-
- free (st->fire);
- st->fire = calloc( st->iWinHeight, sizeof(unsigned char*));
- for (i = 0; i < st->iWinHeight; ++i)
- st->fire[i] = calloc( st->iWinWidth, sizeof(unsigned char));
-
- XDestroyImage( st->pImage );
XGetWindowAttributes( st->dpy, st->window, &XWinAttribs );
- st->pImage = XCreateImage( st->dpy, XWinAttribs.visual, XWinAttribs.depth, ZPixmap, 0, NULL,
- XWinAttribs.width, XWinAttribs.height, BitmapPad( st->dpy ), 0 );
- (st->pImage)->data = calloc((st->pImage)->bytes_per_line, (st->pImage)->height);
-
+ XWinAttribs.width = w;
+ XWinAttribs.height = h;
+ CreateImage (st, &XWinAttribs);
st->draw_i = -1;
}
static Bool
eruption_event (Display *dpy, Window window, void *closure, XEvent *event)
{
+ struct state *st = (struct state *) closure;
+
+ if (event->type == ButtonPress)
+ {
+ new_eruption (st, event->xbutton.x, event->xbutton.y);
+ return True;
+ }
+ else if (screenhack_event_helper (dpy, window, event))
+ {
+ random_eruption (st);
+ return True;
+ }
+
return False;
}
@@ -483,12 +561,8 @@ static void
eruption_free (Display *dpy, Window window, void *closure)
{
struct state *st = (struct state *) closure;
- int i;
- XDestroyImage (st->pImage);
+ DestroyImage (st);
free (st->aiColorVals);
- for (i = 0; i < st->iWinHeight; ++i)
- free (st->fire[i]);
- free (st->fire);
free (st->particles);
XFreeGC (dpy, st->gc);
free (st);
@@ -506,6 +580,8 @@ static const char *eruption_defaults [] = {
"*cooloff: 2",
"*gravity: 1",
"*heat: 256",
+ ".lowrez: true", /* Too slow on Retina screens otherwise */
+ "*useSHM: True",
0
};
@@ -517,6 +593,10 @@ static XrmOptionDescRec eruption_options [] = {
{ "-cooloff", ".cooloff", XrmoptionSepArg, 0 },
{ "-gravity", ".gravity", XrmoptionSepArg, 0 },
{ "-heat", ".heat", XrmoptionSepArg, 0 },
+#ifdef HAVE_XSHM_EXTENSION
+ { "-shm", ".useSHM", XrmoptionNoArg, "True" },
+ { "-no-shm", ".useSHM", XrmoptionNoArg, "False" },
+#endif
{ 0, 0, 0, 0 }
};