/* -*- Mode: C; tab-width: 4 -*- * ballanim --- colour-cycling ball animation. */ #if 0 static const char sccsid[] = "@(#)ballanim.c" #endif /* Copyright (c) 2004 Stuart Brady * Copyright (c) 1994 M.Dobie * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. */ #ifndef STANDALONE #error xscreensaver only #endif # define PROGCLASS "BallAnim" # define HACK_INIT init_ballanim # define HACK_DRAW draw_ballanim # define ballanim_opts xlockmore_opts # define DEFAULTS "*count: 5 \n" \ "*delay: 10000 \n" \ "*ncolors: 16 \n" \ "*useSHM: True \n" # define WRITABLE_COLORS # include "xlockmore.h" /* from the xscreensaver distribution */ # include # ifdef HAVE_XSHM_EXTENSION # include "xshm.h" # endif /* HAVE_XSHM_EXTENSION */ ModeSpecOpt ballanim_opts = { 0, NULL, 0, NULL, NULL }; #include #include /****************************************************************/ #define RESTART 2500 /* number of cycles before restart */ /* a colour specification */ typedef struct Colour { unsigned short r, g, b; } COLOUR , *COLOUR_P; /****************************************************************/ /* data associated with a ballanim window */ typedef struct ballanim_data { /* window paramaters */ Window win; /* the window */ int width, height; /* window size */ int depth; /* depth */ int rdepth; /* real depth (for XImage) */ Visual *visual; /* visual */ /* ballanim drawing parameters */ Bool first_plane; /* doing first plane? */ int start_again; /* when to restart */ /* ballanim drawing parameters */ Bool started, drawing; /* are we drawing? */ int page; /* which page are we drawing? */ int bsize; /* image stuff */ unsigned char *image; /* image data */ XImage *ximage; /* colours stuff */ int colours; /* how many colours possible */ Bool monochrome; /* monochrome? */ Colormap cmap; /* colour map for the window */ XColor *rgb_values; /* colour definitions array */ Bool off_screen; } BALLANIM , *BALLANIM_P; /* apparent colours ^ apparent pages (for now, 2^4) */ #define BALLANIMCOLOURS (1<<4) /* an array of ballanims for each screen */ static BALLANIM_P ballanims = NULL; /****************************************************************/ static char ballgfx_bitmap[256][256]; static char ballgfx_mask[256][256]; /****************************************************************/ static void initialise_ballanim(ModeInfo * mi, BALLANIM_P ballanim) { ballanim->width = 0; /* width and height of window */ ballanim->height = 0; ballanim->depth = 1; ballanim->rdepth = 1; ballanim->visual = NULL; ballanim->start_again = -1; /* restart counter */ ballanim->bsize = 0; /* drawing parameters */ ballanim->started = False; ballanim->drawing = False; /* image stuff */ ballanim->image = NULL; /* image data */ ballanim->ximage = NULL; /* colours stuff */ ballanim->colours = 0; /* how many colours possible */ ballanim->cmap = (Colormap) NULL; ballanim->rgb_values = NULL; /* colour definitions array */ } static void initialise_image(ModeInfo * mi, BALLANIM_P ballanim) { Display *dpy = MI_DISPLAY(mi); if (ballanim->ximage != NULL) XDestroyImage(ballanim->ximage); ballanim->ximage = 0; #ifdef HAVE_XSHM_EXTENSION if (mi->use_shm) { ballanim->ximage = create_xshm_image(dpy, ballanim->visual, ballanim->rdepth, ZPixmap, 0, &mi->shm_info, ballanim->width, ballanim->height); if (!ballanim->ximage) mi->use_shm = False; } #endif /* HAVE_XSHM_EXTENSION */ if (!ballanim->ximage) { ballanim->ximage = XCreateImage(dpy, ballanim->visual, ballanim->rdepth, ZPixmap, 0, 0, ballanim->width, ballanim->height, 8, 0); ballanim->image = (unsigned char *) calloc(ballanim->height, ballanim->ximage->bytes_per_line); ballanim->ximage->data = (char *) ballanim->image; } } static void install_map(Display * dpy, BALLANIM_P ballanim) { /* store it */ XStoreColors(dpy, ballanim->cmap, ballanim->rgb_values, ballanim->colours); } void install_page(ModeInfo * mi, int pagenum) { BALLANIM_P ballanim = &(ballanims[MI_SCREEN(mi)]); int i; for (i=0; i<16; i++) { if (i&(1<rgb_values[i].red = 0xFFFF; ballanim->rgb_values[i].green = 0xFFFF; ballanim->rgb_values[i].blue = 0x0000; } else { ballanim->rgb_values[i].red = 0x0000; ballanim->rgb_values[i].green = 0x0000; ballanim->rgb_values[i].blue = 0x8000; } } install_map(MI_DISPLAY(mi), ballanim); } static void draw_ball(ModeInfo * mi, BALLANIM_P ballanim, int x, int y) { int n, m; int pagemask, val; unsigned long p; int mag = 1; int bsize = ballanim->bsize; int numcols = 16; int numpages = 4; /* check we are within the window */ if ((x < 0) || (x+bsize-1 >= ballanim->width) || (y < 0) || (y+bsize-1 >= ballanim->height)) return; pagemask = 1 << (ballanim->page % numpages); for(m=0; m < bsize; m++) { for(n=0; n < bsize; n++) { if(ballgfx_mask[m/mag][n/mag]) { p = XGetPixel(ballanim->ximage, x+n, y+m); for (val=0; val < numcols; val++) { if (p == ballanim->rgb_values[val].pixel) { break; } } if (val == numcols) val = 0; if (ballgfx_bitmap[m/mag][n/mag]) val |= pagemask; else val &= ~pagemask; XPutPixel(ballanim->ximage, x+n, y+m, ballanim->rgb_values[val].pixel); } } } /* update the screen */ #ifdef HAVE_XSHM_EXTENSION if (mi->use_shm) XShmPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), ballanim->ximage, x, y, x, y, bsize, bsize, False); else #endif /* !HAVE_XSHM_EXTENSION */ /* PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 256 byte memory leak on the next line. */ XPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), ballanim->ximage, x, y, x, y, bsize, bsize); } void init_colours(ModeInfo * mi) { int i; unsigned long *pixels; BALLANIM_P ballanim = &(ballanims[MI_SCREEN(mi)]); mi->npixels=16; pixels = (unsigned long *)malloc(sizeof(*pixels) * ((mi->npixels) + 1)); allocate_writable_colors(MI_DISPLAY(mi), MI_COLORMAP(mi), pixels, &mi->npixels); if (mi->npixels >= 16) { for (i = 0; i < mi->npixels; i++) mi->colors[i].pixel = pixels[i]; free(pixels); XStoreColors(MI_DISPLAY(mi), MI_COLORMAP(mi), mi->colors, mi->npixels); } else { free(pixels); fprintf(stderr, "ballanim: failed to allocate colours\n" "wanted 16; got %i\n", mi->npixels); sleep(2); exit(1); } ballanim->colours = mi->npixels; } void refresh_screen(ModeInfo * mi) { BALLANIM_P ballanim = &(ballanims[MI_SCREEN(mi)]); #ifdef HAVE_XSHM_EXTENSION if (mi->use_shm) XShmPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), ballanim->ximage, 0, 0, 0, 0, ballanim->width, ballanim->height, False); else #endif /* !HAVE_XSHM_EXTENSION */ /* PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 256 byte memory leak on the next line. */ XPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), ballanim->ximage, 0, 0, 0, 0, ballanim->width, ballanim->height); } void initballgfx(int bsize) { int x, y; for(y=0; ywin = window; ballanim->width = MI_WIN_WIDTH(mi); ballanim->height = MI_WIN_HEIGHT(mi); ballanim->depth = MI_WIN_DEPTH(mi); ballanim->rdepth = ballanim->depth; ballanim->visual = MI_VISUAL(mi); if (ballanim->depth > 16) ballanim->depth = 16; /* initialise image for speeding up drawing */ initialise_image(mi, ballanim); /* clear the window (before setting the colourmap) */ XClearWindow(display, MI_WINDOW(mi)); ballanim->rgb_values = mi->colors; ballanim->colours = mi->npixels; /* ballanim->fixed_colourmap = !mi->writable_p;*/ fprintf(stderr, "init_colors %i\n", MI_SCREEN(mi)); init_colours(mi); ballanim->cmap = MI_COLORMAP(mi); /* we are off */ ballanim->started = True; ballanim->drawing = False; { int x, y; int pixel = ballanim->rgb_values[0].pixel; for(y=0; yheight; y++) for(x=0; xwidth; x++) XPutPixel(ballanim->ximage, x, y, pixel); refresh_screen(mi); } if ((float)ballanim->width / ballanim->height >= 1.25) ballanim->bsize = ballanim->height / 8; else ballanim->bsize = ballanim->width / 10; initballgfx(ballanim->bsize); } void get_newpos(BALLANIM_P ballanim, int *x, int *y) { int maxa = 200; int maxb = maxa*16; static int a = 0; static int b; static int i = 0; static int tick = 0; float xf; float yf; if (!i) { i = 1; b = 0; /* b = -maxb; */ } xf = (cos(a*2*M_PI/maxa) + 1) / 2; yf = (-sin(a*2*M_PI/maxa) * (float)b/maxb + 1) / 2; *x = (ballanim->width-ballanim->bsize) * xf; *y = (ballanim->height-ballanim->bsize) * yf; a++; if (a>=maxa) a = 0; if (!tick) { b++; if (b>=maxb) tick = 1; } else { b--; if (b<=-maxb) tick = 0; } } void draw_ballanim(ModeInfo * mi) { BALLANIM_P ballanim = &(ballanims[MI_SCREEN(mi)]); /* are we going? */ if (ballanim->started) { int x, y; get_newpos(ballanim, &x, &y); /* draw a point */ draw_ball(mi, ballanim, x, y); XFlush(MI_DISPLAY(mi)); usleep(7500); install_page(mi, ballanim->page); XFlush(MI_DISPLAY(mi)); ballanim->page++; ballanim->page %= 4; } else if (ballanim->start_again == 0) { /* reset the counter */ ballanim->start_again = -1; /* free the old colours */ XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi)); free_colors (MI_DISPLAY(mi), MI_COLORMAP(mi), mi->colors, mi->npixels); /* start again */ init_ballanim(mi); } else /* decrement the counter */ ballanim->start_again--; } void release_ballanim(ModeInfo * mi) { /* does the ballanims array exist? */ if (ballanims != NULL) { int i; /* free them all */ for (i = 0; i < MI_NUM_SCREENS(mi); i++) { BALLANIM_P ballanim = &(ballanims[i]); if (ballanim->cmap != (Colormap) NULL) XFreeColormap(MI_DISPLAY(mi), ballanim->cmap); if (ballanim->rgb_values != NULL) XFree((void *) ballanim->rgb_values); if (ballanim->ximage != NULL) XDestroyImage(ballanim->ximage); } /* deallocate an array, one entry for each screen */ (void) free((void *) ballanims); ballanims = NULL; } } void refresh_ballanim(ModeInfo * mi) { refresh_screen(mi); }