From 2954208d00d422b34fa3a69631b0a091f17a349d Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 2 Dec 2020 08:23:52 +0100 Subject: 5.44 --- hacks/eruption.c | 330 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 205 insertions(+), 125 deletions(-) (limited to 'hacks/eruption.c') 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 : 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 #include #include "screenhack.h" +#include "xshm.h" + +#ifdef HAVE_INTTYPES_H +# include +#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; ifire ); - /* 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 } }; -- cgit v1.2.3-55-g7522