X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fbubbles.c;h=fe5ccef0585116a546358805185b045eb3529461;hb=a94197e76a5dea5cb60542840809d6c20d0abbf3;hp=913fe03726df2c676d19b80902dfd24cbdb2a5db;hpb=f65151994eba80ecabcdac6eef6fa0dde7e2d45b;p=xscreensaver diff --git a/hacks/bubbles.c b/hacks/bubbles.c index 913fe037..fe5ccef0 100644 --- a/hacks/bubbles.c +++ b/hacks/bubbles.c @@ -1,6 +1,6 @@ /* bubbles.c - frying pan / soft drink in a glass simulation */ -/*$Id: bubbles.c,v 1.16 1998/11/19 07:25:01 jwz Exp $*/ +/*$Id: bubbles.c,v 1.18 2002/01/17 02:16:04 jwz Exp $*/ /* * Copyright (C) 1995-1996 James Macnicol @@ -36,12 +36,11 @@ * and things are _much_ nicer.) * * Author: James Macnicol - * Internet E-mail : J.Macnicol@student.anu.edu.au + * Internet E-mail : j-macnicol@adfa.edu.au */ #include #include "screenhack.h" -#include "bubbles.h" #include @@ -60,9 +59,11 @@ # include #endif #include "yarandom.h" +#include "bubbles.h" +#include "xpm-pixmap.h" -#ifdef HAVE_XPM -# include +#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM) +# define FANCY_BUBBLES #endif /* @@ -72,6 +73,7 @@ extern void init_default_bubbles(void); extern int num_default_bubbles; extern char **default_bubbles[]; +static int drop_bubble( Bubble *bb ); char *progclass = "Bubbles"; @@ -83,19 +85,24 @@ char *defaults [] = { "*delay: 800", "*quiet: false", "*nodelay: false", + "*drop: false", + "*trails: false", "*3D: false", 0 }; XrmOptionDescRec options [] = { { "-simple", ".simple", XrmoptionNoArg, "true" }, -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES { "-broken", ".broken", XrmoptionNoArg, "true" }, -#endif /* HAVE_XPM */ +#endif { "-quiet", ".quiet", XrmoptionNoArg, "true" }, { "-nodelay", ".nodelay", XrmoptionNoArg, "true" }, { "-3D", ".3D", XrmoptionNoArg, "true" }, { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-drop", ".drop", XrmoptionNoArg, "true" }, + { "-rise", ".rise", XrmoptionNoArg, "true" }, + { "-trails", ".trails", XrmoptionNoArg, "true" }, { 0, 0, 0, 0 } }; @@ -128,15 +135,16 @@ static Visual *defvisual; static int bubble_min_radius; static int bubble_max_radius; static long *bubble_areas; +static int *bubble_droppages; static GC draw_gc, erase_gc; -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES static int num_bubble_pixmaps; static Bubble_Step **step_pixmaps; -#endif /* HAVE_XPM */ +#endif /* Options stuff */ -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES static Bool simple = False; #else static Bool simple = True; @@ -144,6 +152,9 @@ static Bool simple = True; static Bool broken = False; static Bool quiet = False; static Bool threed = False; +static Bool drop = False; +static Bool trails = False; +static int drop_dir; static int delay; /* @@ -215,7 +226,7 @@ turned off if DEBUG isn't set. */ bb->radius, bb->x, bb->y, bb->magic, bb->cell_index); die_bad_bubble(bb); } -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES } else { if ((bb->x < 0) || (bb->x > screen_width) || (bb->y < 0) || (bb->y > screen_height) || @@ -226,7 +237,7 @@ turned off if DEBUG isn't set. */ bb->radius, bb->x, bb->y, bb->magic, bb->cell_index); die_bad_bubble(bb); } -#endif /* HAVE_XPM */ +#endif } #endif /* DEBUG */ return 0; @@ -428,20 +439,20 @@ adjust_areas (void) long factor; int i; -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES if (simple) maxarea = bubble_areas[bubble_max_radius+1]; else maxarea = step_pixmaps[num_bubble_pixmaps]->area; -#else +#else /* !FANCY_BUBBLES */ maxarea = bubble_areas[bubble_max_radius+1]; -#endif /* HAVE_XPM */ +#endif /* !FANCY_BUBBLES */ maxvalue = (double)screen_width * 2.0 * (double)maxarea; factor = (long)ceil(maxvalue / (double)LONG_MAX); if (factor > 1) { /* Overflow will occur in weighted_mean(). We must divide areas each by factor so it will never do so. */ -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES if (simple) { for (i = bubble_min_radius; i <= bubble_max_radius+1; i++) { bubble_areas[i] /= factor; @@ -461,13 +472,13 @@ adjust_areas (void) #endif /* DEBUG */ } } -#else +#else /* !FANCY_BUBBLES */ for (i = bubble_min_radius; i <= bubble_max_radius+1; i++) { bubble_areas[i] /= factor; if (bubble_areas[i] == 0) bubble_areas[i] = 1; } -#endif /* HAVE_XPM */ +#endif /* !FANCY_BUBBLES */ } #ifdef DEBUG printf("maxarea = %ld\n", maxarea); @@ -497,12 +508,12 @@ size. */ if (simple) { rv->radius = bubble_min_radius; rv->area = bubble_areas[bubble_min_radius]; -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES } else { rv->step = 0; rv->radius = step_pixmaps[0]->radius; rv->area = step_pixmaps[0]->area; -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } rv->visible = 0; rv->magic = BUBBLE_MAGIC; @@ -530,7 +541,7 @@ show_bubble(Bubble *bb) (bb->y - bb->radius), bb->radius*2, bb->radius*2, 0, 360*64); } else { -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES XSetClipOrigin(defdsp, step_pixmaps[bb->step]->draw_gc, (bb->x - bb->radius), (bb->y - bb->radius)); @@ -541,7 +552,7 @@ show_bubble(Bubble *bb) (bb->radius * 2), (bb->x - bb->radius), (bb->y - bb->radius)); -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } } } @@ -563,7 +574,7 @@ hide_bubble(Bubble *bb) (bb->y - bb->radius), bb->radius*2, bb->radius*2, 0, 360*64); } else { -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES if (! broken) { XSetClipOrigin(defdsp, step_pixmaps[bb->step]->erase_gc, (bb->x - bb->radius), (bb->y - bb->radius)); @@ -574,7 +585,7 @@ hide_bubble(Bubble *bb) (bb->radius * 2), (bb->radius * 2)); } -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } } } @@ -747,38 +758,50 @@ bubble_eat(Bubble *diner, Bubble *food) diner->area += food->area; delete_bubble_in_mesh(food, DELETE_BUBBLE); - if ((simple) && (diner->area > bubble_areas[bubble_max_radius])) { - delete_bubble_in_mesh(diner, DELETE_BUBBLE); - return 0; + if (drop) { + if ((simple) && (diner->area > bubble_areas[bubble_max_radius])) { + diner->area = bubble_areas[bubble_max_radius]; + } +#ifdef FANCY_BUBBLES + if ((! simple) && (diner->area > step_pixmaps[num_bubble_pixmaps]->area)) { + diner->area = step_pixmaps[num_bubble_pixmaps]->area; + } +#endif /* FANCY_BUBBLES */ } -#ifdef HAVE_XPM - if ((! simple) && (diner->area > - step_pixmaps[num_bubble_pixmaps]->area)) { - delete_bubble_in_mesh(diner, DELETE_BUBBLE); - return 0; + else { + if ((simple) && (diner->area > bubble_areas[bubble_max_radius])) { + delete_bubble_in_mesh(diner, DELETE_BUBBLE); + return 0; + } +#ifdef FANCY_BUBBLES + if ((! simple) && (diner->area > + step_pixmaps[num_bubble_pixmaps]->area)) { + delete_bubble_in_mesh(diner, DELETE_BUBBLE); + return 0; + } +#endif /* FANCY_BUBBLES */ } -#endif /* HAVE_XPM */ if (simple) { if (diner->area > bubble_areas[diner->radius + 1]) { /* Move the bubble to a new radius */ i = diner->radius; - while (diner->area > bubble_areas[i+1]) - ++i; + while ((i < bubble_max_radius - 1) && (diner->area > bubble_areas[i+1])) + ++i; diner->radius = i; } show_bubble(diner); -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES } else { if (diner->area > step_pixmaps[diner->step+1]->area) { i = diner->step; - while (diner->area > step_pixmaps[i+1]->area) - ++i; + while ((i < num_bubble_pixmaps - 1) && (diner->area > step_pixmaps[i+1]->area)) + ++i; diner->step = i; diner->radius = step_pixmaps[diner->step]->radius; } show_bubble(diner); -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } /* Now adjust locations and cells if need be */ @@ -883,33 +906,133 @@ insert_new_bubble(Bubble *tmp) nextbub = tmp; touch = get_closest_bubble(nextbub); - while (! null_bubble(touch)) { - switch (merge_bubbles(nextbub, touch)) { - case 2: - /* touch ate nextbub and survived */ - nextbub = touch; - break; - case 1: - /* nextbub ate touch and survived */ - break; - case 0: - /* somebody ate someone else but they exploded */ - nextbub = (Bubble *)NULL; - break; - default: - /* something went wrong */ - fprintf(stderr, "Error occurred in insert_new_bubble()\n"); - exit(1); - } - /* Check to see if there are any other bubbles still in the area - and if we need to do this all over again for them. */ - if (! null_bubble(nextbub)) - touch = get_closest_bubble(nextbub); - else - touch = (Bubble *)NULL; + if (null_bubble(touch)) + return; + + while (1) { + + /* Merge all touching bubbles */ + while (! null_bubble(touch)) { + switch (merge_bubbles(nextbub, touch)) { + case 2: + /* touch ate nextbub and survived */ + nextbub = touch; + break; + case 1: + /* nextbub ate touch and survived */ + break; + case 0: + /* somebody ate someone else but they exploded */ + nextbub = (Bubble *)NULL; + break; + default: + /* something went wrong */ + fprintf(stderr, "Error occurred in insert_new_bubble()\n"); + exit(1); + } + + /* Check to see if any bubble survived. */ + if (null_bubble(nextbub)) + break; + + /* Check to see if there are any other bubbles still in the area + and if we need to do this all over again for them. */ + touch = get_closest_bubble(nextbub); + } + + if (null_bubble(nextbub)) + break; + + /* Shift bubble down. Break if we run off the screen. */ + if (drop) { + if (drop_bubble( nextbub ) == -1) + break; + } + + /* Check to see if there are any other bubbles still in the area + and if we need to do this all over again for them. */ + touch = get_closest_bubble(nextbub); + if (null_bubble(touch)) { + /* We also continue every so often if we're dropping and the bubble is at max size */ + if (drop) { + if (simple) { + if ((nextbub->area >= bubble_areas[bubble_max_radius - 1]) && (random() % 2 == 0)) + continue; + } +#ifdef FANCY_BUBBLES + else { + if ((nextbub->step >= num_bubble_pixmaps - 1) && (random() % 2 == 0)) + continue; + } +#endif /* FANCY_BUBBLES */ + } + break; + } + } } + +static void +leave_trail( Bubble *bb ) +{ + Bubble *tmp; + + tmp = new_bubble(); + tmp->x = bb->x; + tmp->y = bb->y - ((bb->radius + 10) * drop_dir); + tmp->cell_index = pixel_to_mesh(tmp->x, tmp->y); + add_to_mesh(tmp); + insert_new_bubble(tmp); + show_bubble( tmp ); +} + + +static int +drop_bubble( Bubble *bb ) +{ + int newmi; + + hide_bubble( bb ); + + if (simple) + (bb->y) += (bubble_droppages[bb->radius] * drop_dir); +#ifdef FANCY_BUBBLES + else + (bb->y) += (step_pixmaps[bb->step]->droppage * drop_dir); +#endif /* FANCY_BUBBLES */ + if ((bb->y < 0) || (bb->y > screen_height)) { + delete_bubble_in_mesh( bb, DELETE_BUBBLE ); + return -1; + } + + show_bubble( bb ); + + /* Now adjust locations and cells if need be */ + newmi = pixel_to_mesh(bb->x, bb->y); + if (newmi != bb->cell_index) { + delete_bubble_in_mesh(bb, KEEP_BUBBLE); + bb->cell_index = newmi; + add_to_mesh(bb); + } + + if (trails) { + if (simple) { + if ((bb->area >= bubble_areas[bubble_max_radius - 1]) && (random() % 2 == 0)) + leave_trail( bb ); + } +#ifdef FANCY_BUBBLES + else { + if ((bb->step >= num_bubble_pixmaps - 1) && (random() % 2 == 0)) + leave_trail( bb ); + } +#endif /* FANCY_BUBBLES */ + } + + return 0; +} + + #ifdef DEBUG static int get_length_of_bubble_list(Bubble *bb) @@ -931,7 +1054,7 @@ get_length_of_bubble_list(Bubble *bb) * still check for XPM, though! */ -#ifdef HAVE_XPM +#ifdef FANCY_BUBBLES /* * Pixmaps without file I/O (but do have XPM) @@ -1042,6 +1165,10 @@ make_pixmap_array(Bubble_Step *list) prevrad = step_pixmaps[ind]->radius; } #endif /* DEBUG */ + + /* Now populate the droppage values */ + for (ind = 0; ind < num_bubble_pixmaps; ind++) + step_pixmaps[ind]->droppage = MAX_DROPPAGE * ind / num_bubble_pixmaps; } static void @@ -1052,7 +1179,6 @@ make_pixmap_from_default(char **pixmap_data, Bubble_Step *bl) This is virtually copied verbatim from make_pixmap_from_file() above and changes made to either should be propagated onwards! */ { - int result; XGCValues gcv; #ifdef DEBUG @@ -1067,49 +1193,16 @@ changes made to either should be propagated onwards! */ exit(1); } - bl->xpmattrs.valuemask = 0; - -#ifdef XpmCloseness - bl->xpmattrs.valuemask |= XpmCloseness; - bl->xpmattrs.closeness = 40000; -#endif -#ifdef XpmVisual - bl->xpmattrs.valuemask |= XpmVisual; - bl->xpmattrs.visual = defvisual; -#endif -#ifdef XpmDepth - bl->xpmattrs.valuemask |= XpmDepth; - bl->xpmattrs.depth = screen_depth; -#endif -#ifdef XpmColormap - bl->xpmattrs.valuemask |= XpmColormap; - bl->xpmattrs.colormap = defcmap; -#endif - - - /* This is the only line which is different from make_pixmap_from_file() */ - result = XpmCreatePixmapFromData(defdsp, defwin, pixmap_data, &bl->ball, - &bl->shape_mask, &bl->xpmattrs); - - switch(result) { - case XpmColorError: - fprintf(stderr, "xpm: color substitution performed\n"); - /* fall through */ - case XpmSuccess: - bl->radius = MAX(bl->xpmattrs.width, bl->xpmattrs.height) / 2; +#ifdef FANCY_BUBBLES + { + int w, h; + bl->ball = xpm_data_to_pixmap (defdsp, defwin, (char **) pixmap_data, + &w, &h, &bl->shape_mask); + bl->radius = MAX(w, h) / 2; bl->area = calc_bubble_area(bl->radius); - break; - case XpmColorFailed: - fprintf(stderr, "xpm: color allocation failed\n"); - exit(1); - case XpmNoMemory: - fprintf(stderr, "xpm: out of memory\n"); - exit(1); - default: - fprintf(stderr, "xpm: unknown error code %d\n", result); - exit(1); } - +#endif /* FANCY_BUBBLES */ + gcv.plane_mask = AllPlanes; gcv.foreground = default_fg_pixel; gcv.function = GXcopy; @@ -1153,7 +1246,7 @@ default_to_pixmaps (void) make_pixmap_array(pixmap_list); } -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ /* @@ -1165,7 +1258,7 @@ static void get_resources(Display *dpy, Window window) /* Get the appropriate X resources and warn about any inconsistencies. */ { - Bool nodelay; + Bool nodelay, rise; XWindowAttributes xgwa; Colormap cmap; XGetWindowAttributes (dpy, window, &xgwa); @@ -1188,6 +1281,17 @@ get_resources(Display *dpy, Window window) if (delay < 0) delay = 0; + drop = get_boolean_resource("drop", "Boolean"); + rise = get_boolean_resource("rise", "Boolean"); + trails = get_boolean_resource("trails", "Boolean"); + if (drop && rise) { + fprintf( stderr, "Sorry, bubbles can't both drop and rise\n" ); + exit(1); + } + drop_dir = (drop ? 1 : -1); + if (drop || rise) + drop = 1; + default_fg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap); default_bg_pixel = get_pixel_resource ("background", "Background", dpy, @@ -1200,11 +1304,11 @@ get_resources(Display *dpy, Window window) if (! quiet) fprintf(stderr, "-broken not available in simple mode\n"); } else { -#ifndef HAVE_XPM +#ifndef FANCY_BUBBLES simple = 1; -#else +#else /* FANCY_BUBBLES */ broken = get_boolean_resource("broken", "Boolean"); -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ } } @@ -1255,20 +1359,27 @@ init_bubbles (Display *dpy, Window window) for (i = bubble_min_radius; i <= (bubble_max_radius+1); i++) bubble_areas[i] = calc_bubble_area(i); + /* Now populate the droppage values */ + bubble_droppages = (int *)xmalloc((bubble_max_radius + 2) * sizeof(int)); + for (i = 0; i < bubble_min_radius; i++) + bubble_droppages[i] = 0; + for (i = bubble_min_radius; i <= (bubble_max_radius+1); i++) + bubble_droppages[i] = MAX_DROPPAGE * (i - bubble_min_radius) / (bubble_max_radius - bubble_min_radius); + mesh_length = (2 * bubble_max_radius) + 3; } else { -#ifndef HAVE_XPM +#ifndef FANCY_BUBBLES fprintf(stderr, - "Bug: simple mode code not set but HAVE_XPM not defined\n"); + "Bug: simple mode code not set but FANCY_BUBBLES not defined\n"); exit(1); -#else +#else /* FANCY_BUBBLES */ /* Make sure all #ifdef sort of things have been taken care of in get_resources(). */ default_to_pixmaps(); /* Set mesh length */ mesh_length = (2 * step_pixmaps[num_bubble_pixmaps-1]->radius) + 3; -#endif /* HAVE_XPM */ +#endif /* FANCY_BUBBLES */ /* Am I missing something in here??? */ }