diff options
author | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
commit | d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch) | |
tree | cbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /hacks/halftone.c | |
download | xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip |
Original 5.40
Diffstat (limited to 'hacks/halftone.c')
-rw-r--r-- | hacks/halftone.c | 397 |
1 files changed, 397 insertions, 0 deletions
diff --git a/hacks/halftone.c b/hacks/halftone.c new file mode 100644 index 0000000..b70a636 --- /dev/null +++ b/hacks/halftone.c @@ -0,0 +1,397 @@ +/* halftone, Copyright (c) 2002 by Peter Jaric <peter@jaric.org> + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + * + * Description: + * Draws the gravitational force in each point on the screen seen + * through a halftone dot pattern. The force is calculated from a set + * of moving mass points. View it from a distance for best effect. + */ + +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "screenhack.h" + +#define DEFAULT_DELAY 10000 +#define DEFAULT_SPACING 14 +#define DEFAULT_SIZE_FACTOR 1.5 +#define DEFAULT_COUNT 10 +#define DEFAULT_MIN_MASS 0.001 +#define DEFAULT_MAX_MASS 0.02 +#define DEFAULT_MIN_SPEED 0.001 +#define DEFAULT_MAX_SPEED 0.02 + + +typedef struct +{ + /* halftone dots */ + double * dots; + int dots_width; + int dots_height; + int spacing; + int max_dot_size; + + /* Moving gravity points */ + int gravity_point_count; + + double* gravity_point_x; + double* gravity_point_y; + double* gravity_point_mass; + double* gravity_point_x_inc; + double* gravity_point_y_inc; + + /* X stuff */ + Display *dpy; + Window window; + GC gc; + + int ncolors; + XColor *colors; + int color0, color1; + int color_tick, cycle_speed; + + /* Off screen buffer */ + Pixmap buffer; + GC buffer_gc; + int buffer_width; + int buffer_height; + + int delay; + +} halftone_screen; + + +static void update_buffer(halftone_screen *halftone, XWindowAttributes * attrs) +{ + if (halftone->buffer_width != attrs->width || + halftone->buffer_height != attrs->height) + { + XGCValues gc_values; + + if (halftone->buffer_width != -1 && + halftone->buffer_height != -1) + { + if (halftone->buffer != halftone->window) + XFreePixmap(halftone->dpy, halftone->buffer); + XFreeGC(halftone->dpy, halftone->buffer_gc); + } + + halftone->buffer_width = attrs->width; + halftone->buffer_height = attrs->height; +#ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ + halftone->buffer = halftone->window; +#else + halftone->buffer = XCreatePixmap(halftone->dpy, halftone->window, halftone->buffer_width, halftone->buffer_height, attrs->depth); +#endif + + halftone->buffer_gc = XCreateGC(halftone->dpy, halftone->buffer, 0, &gc_values); + } +} + +static void update_dot_attributes(halftone_screen *halftone, XWindowAttributes * attrs) +{ + double dots_width = attrs->width / halftone->spacing + 1; + double dots_height = attrs->height / halftone->spacing + 1; + + if (halftone->dots == NULL || + (dots_width != halftone->dots_width || + dots_height != halftone->dots_height)) + { + if (halftone->dots != NULL) + free(halftone->dots); + + halftone->dots_width = dots_width; + halftone->dots_height = dots_height; + halftone->dots = (double *) malloc(halftone->dots_width * halftone->dots_height * sizeof(double)); + } +} + +static void * +halftone_init (Display *dpy, Window window) +{ + int x, y, i; + int count; + int spacing; + double factor; + double min_mass; + double max_mass; + double min_speed; + double max_speed; + XGCValues gc_values; + XWindowAttributes attrs; + halftone_screen *halftone; + + halftone = (halftone_screen *) calloc (1, sizeof(halftone_screen)); + + halftone->dpy = dpy; + halftone->window = window; + + halftone->delay = get_integer_resource (dpy, "delay", "Integer"); + halftone->delay = (halftone->delay < 0 ? DEFAULT_DELAY : halftone->delay); + + halftone->gc = XCreateGC (halftone->dpy, halftone->window, 0, &gc_values); + + halftone->buffer_width = -1; + halftone->buffer_height = -1; + halftone->dots = NULL; + + /* Read command line arguments and set all settings. */ + count = get_integer_resource (dpy, "count", "Count"); + halftone->gravity_point_count = count < 1 ? DEFAULT_COUNT : count; + + spacing = get_integer_resource (dpy, "spacing", "Integer"); + halftone->spacing = spacing < 1 ? DEFAULT_SPACING : spacing; + + factor = get_float_resource (dpy, "sizeFactor", "Double"); + halftone->max_dot_size = + (factor < 0 ? DEFAULT_SIZE_FACTOR : factor) * halftone->spacing; + + min_mass = get_float_resource (dpy, "minMass", "Double"); + min_mass = min_mass < 0 ? DEFAULT_MIN_MASS : min_mass; + + max_mass = get_float_resource (dpy, "maxMass", "Double"); + max_mass = max_mass < 0 ? DEFAULT_MAX_MASS : max_mass; + max_mass = max_mass < min_mass ? min_mass : max_mass; + + min_speed = get_float_resource (dpy, "minSpeed", "Double"); + min_speed = min_speed < 0 ? DEFAULT_MIN_SPEED : min_speed; + + max_speed = get_float_resource (dpy, "maxSpeed", "Double"); + max_speed = max_speed < 0 ? DEFAULT_MAX_SPEED : max_speed; + max_speed = max_speed < min_speed ? min_speed : max_speed; + + + /* Set up the moving gravity points. */ + halftone->gravity_point_x = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_y = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_mass = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_x_inc = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + halftone->gravity_point_y_inc = (double *) malloc(halftone->gravity_point_count * sizeof(double)); + + for (i = 0; i < halftone->gravity_point_count; i++) + { + halftone->gravity_point_x[i] = frand(1); + halftone->gravity_point_y[i] = frand(1); + halftone->gravity_point_mass[i] = min_mass + (max_mass - min_mass) * frand(1); + halftone->gravity_point_x_inc[i] = min_speed + (max_speed - min_speed) * frand(1); + halftone->gravity_point_y_inc[i] = min_speed + (max_speed - min_speed) * frand(1); + } + + + /* Set up the dots. */ + XGetWindowAttributes(halftone->dpy, halftone->window, &attrs); + + halftone->ncolors = get_integer_resource (dpy, "colors", "Colors"); + if (halftone->ncolors < 4) halftone->ncolors = 4; + halftone->colors = (XColor *) calloc(halftone->ncolors, sizeof(XColor)); + make_smooth_colormap (attrs.screen, attrs.visual, attrs.colormap, + halftone->colors, &halftone->ncolors, + True, 0, False); + halftone->color0 = 0; + halftone->color1 = halftone->ncolors / 2; + halftone->cycle_speed = get_integer_resource (dpy, "cycleSpeed", "CycleSpeed"); + halftone->color_tick = 0; + + update_buffer(halftone, &attrs); + update_dot_attributes(halftone, &attrs); + + for (x = 0; x < halftone->dots_width; x++) + for (y = 0; y < halftone->dots_height; y++) + { + halftone->dots[x + y * halftone->dots_width] = 0; + } + + return halftone; +} + + + +static void fill_circle(Display *dpy, Window window, GC gc, int x, int y, int size) +{ + int start_x = x - (size / 2); + int start_y = y - (size / 2); + unsigned int width = size; + unsigned int height = size; + int angle1 = 0; + int angle2 = 360 * 64; /* A full circle */ + + XFillArc (dpy, window, gc, + start_x, start_y, width, height, + angle1, angle2); +} + +static void repaint_halftone(halftone_screen *halftone) +{ + int x, y; + /* + int x_offset = halftone->spacing / 2; + int y_offset = halftone->spacing / 2; + */ + int x_offset = 0; + int y_offset = 0; + + + /* Fill buffer with background color */ + XSetForeground (halftone->dpy, halftone->buffer_gc, + halftone->colors[halftone->color0].pixel); + XFillRectangle(halftone->dpy, halftone->buffer, halftone->buffer_gc, 0, 0, halftone->buffer_width, halftone->buffer_height); + + /* Draw dots on buffer */ + XSetForeground (halftone->dpy, halftone->buffer_gc, + halftone->colors[halftone->color1].pixel); + + if (halftone->color_tick++ >= halftone->cycle_speed) + { + halftone->color_tick = 0; + halftone->color0 = (halftone->color0 + 1) % halftone->ncolors; + halftone->color1 = (halftone->color1 + 1) % halftone->ncolors; + } + + for (x = 0; x < halftone->dots_width; x++) + for (y = 0; y < halftone->dots_height; y++) + fill_circle(halftone->dpy, halftone->buffer, halftone->buffer_gc, + x_offset + x * halftone->spacing, y_offset + y * halftone->spacing, + halftone->max_dot_size * halftone->dots[x + y * halftone->dots_width]); + + /* Copy buffer to window */ + if (halftone->buffer != halftone->window) + XCopyArea(halftone->dpy, halftone->buffer, halftone->window, halftone->gc, 0, 0, halftone->buffer_width, halftone->buffer_height, 0, 0); +} + +static double calculate_gravity(halftone_screen *halftone, int x, int y) +{ + int i; + double gx = 0; + double gy = 0; + + for (i = 0; i < halftone->gravity_point_count; i++) + { + double dx = ((double) x) - halftone->gravity_point_x[i] * halftone->dots_width; + double dy = ((double) y) - halftone->gravity_point_y[i] * halftone->dots_height; + double distance = sqrt(dx * dx + dy * dy); + + if (distance != 0) + { + double gravity = halftone->gravity_point_mass[i] / (distance * distance / (halftone->dots_width * halftone->dots_height)); + + gx += (dx / distance) * gravity; + gy += (dy / distance) * gravity; + } + } + + return sqrt(gx * gx + gy * gy); +} + +static void update_halftone(halftone_screen *halftone) +{ + int x, y, i; + XWindowAttributes attrs; + + XGetWindowAttributes(halftone->dpy, halftone->window, &attrs); + + /* Make sure we have a valid buffer */ + update_buffer(halftone, &attrs); + + /* Make sure all dot attributes (spacing, width, height, etc) are correct */ + update_dot_attributes(halftone, &attrs); + + /* Move gravity points */ + for (i = 0; i < halftone->gravity_point_count; i++) + { + halftone->gravity_point_x_inc[i] = + (halftone->gravity_point_x[i] >= 1 || halftone->gravity_point_x[i] <= 0 ? + -halftone->gravity_point_x_inc[i] : + halftone->gravity_point_x_inc[i]); + halftone->gravity_point_y_inc[i] = + (halftone->gravity_point_y[i] >= 1 || halftone->gravity_point_y[i] <= 0 ? + -halftone->gravity_point_y_inc[i] : + halftone->gravity_point_y_inc[i]); + + halftone->gravity_point_x[i] += halftone->gravity_point_x_inc[i]; + halftone->gravity_point_y[i] += halftone->gravity_point_y_inc[i]; + } + + /* Update gravity in each dot .*/ + for (x = 0; x < halftone->dots_width; x++) + for (y = 0; y < halftone->dots_height; y++) + { + double gravity = calculate_gravity(halftone, x, y); + + halftone->dots[x + y * halftone->dots_width] = (gravity > 1 ? 1 : (gravity < 0 ? 0 : gravity)); + } +} + + +static unsigned long +halftone_draw (Display *dpy, Window window, void *closure) +{ + halftone_screen *halftone = (halftone_screen *) closure; + + repaint_halftone(halftone); + update_halftone(halftone); + + return halftone->delay; +} + + +static void +halftone_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +halftone_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +halftone_free (Display *dpy, Window window, void *closure) +{ + halftone_screen *halftone = (halftone_screen *) closure; + free (halftone); +} + + +static const char *halftone_defaults [] = { + ".background: Black", + "*delay: 10000", + "*count: 10", + "*minMass: 0.001", + "*maxMass: 0.02", + "*minSpeed: 0.001", + "*maxSpeed: 0.02", + "*spacing: 14", + "*sizeFactor: 1.5", + "*colors: 200", + "*cycleSpeed: 10", +#ifdef HAVE_MOBILE + "*ignoreRotation: True", +#endif + 0 +}; + +static XrmOptionDescRec halftone_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-minmass", ".minMass", XrmoptionSepArg, 0 }, + { "-maxmass", ".maxMass", XrmoptionSepArg, 0 }, + { "-minspeed", ".minSpeed", XrmoptionSepArg, 0 }, + { "-maxspeed", ".maxSpeed", XrmoptionSepArg, 0 }, + { "-spacing", ".spacing", XrmoptionSepArg, 0 }, + { "-sizefactor", ".sizeFactor", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-cycle-speed", ".cycleSpeed", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + + +XSCREENSAVER_MODULE ("Halftone", halftone) |