3 * Copyright (c) 2006-2014 Emilio Del Tessandoro <emilio.deltessa@gmail.com>
5 * Directly ported code from complexification.net Binary Ring art
6 * http://www.complexification.net/gallery/machines/binaryRing/appletm/BinaryRing_m.pde
10 * Albuquerque, New Mexico
11 * complexification.net
13 * Directly based the hacks of:
15 * xscreensaver, Copyright (c) 1997, 1998, 2002 Jamie Zawinski <jwz@jwz.org>
17 * Permission to use, copy, modify, distribute, and sell this software and its
18 * documentation for any purpose is hereby granted without fee, provided that
19 * the above copyright notice appear in all copies and that both that
20 * copyright notice and this permission notice appear in supporting
21 * documentation. No representations are made about the suitability of this
22 * software for any purpose. It is provided "as is" without express or
26 #include "screenhack.h"
33 typedef unsigned long uint32_t;
40 #define swap(a, b) do { __typeof__(a) tmp; tmp = a; a = b; b = tmp; } while(0)
41 #define frand1() ((((int) random() ) << 1) * 4.65661287524579692411E-10)
42 #define min(a,b) ((a)<(b)?(a):(b))
43 #define max(a,b) ((a)>(b)?(a):(b))
45 /* better if signed */
46 typedef uint32_t pixel_t;
54 int age; /* age from 0 to ageMax */
65 particle_t* particles;
68 Display *display; /* variables for the X stuff */
78 Pixmap pix; /* for reshape */
79 XImage* buf; /* buffer */
88 static void point2rgb(int depth, pixel_t c, int *r, int *g, int *b)
94 /* This program idiotically does not go through a color map, so
95 we have to hardcode in knowledge of how jwxyz.a packs pixels!
96 Fix it to go through st->colors[st->ncolors] instead!
98 *r = (c & 0x00ff0000) >> 16;
99 *g = (c & 0x0000ffff) >> 8;
100 *b = (c & 0x000000ff);
102 *g = (c & 0xff00) >> 8;
103 *r = (c & 0xff0000) >> 16;
108 *g = ((c >> 5) & 0x3f) << 2;
109 *r = ((c >> 11) & 0x1f) << 3;
110 *b = (c & 0x1f) << 3;
113 *g = ((c >> 5) & 0x1f) << 3;
114 *r = ((c >> 10) & 0x1f) << 3;
115 *b = (c & 0x1f) << 3;
120 static pixel_t rgb2point(int depth, int r, int g, int b)
128 /* This program idiotically does not go through a color map, so
129 we have to hardcode in knowledge of how jwxyz.a packs pixels!
130 Fix it to go through st->colors[st->ncolors] instead!
132 ret = 0xFF000000 | (r << 16) | (g << 8) | b;
134 ret |= (r << 16) | (g << 8) | b;
138 ret = ((r>>3) << 11) | ((g>>2)<<5) | (b>>3);
141 ret = ((r>>3) << 10) | ((g>>3)<<5) | (b>>3);
148 void print_color ( struct state* st, pixel_t color );
149 /* alpha blended point drawing -- this is Not Right and will likely fail on
150 * non-intel platforms as it is now, needs fixing
154 void draw_point ( struct state* st,
155 int x, int y, pixel_t myc, float a ) {
157 int or = 0, og = 0, ob = 0;
158 int r = 0, g = 0, b = 0;
162 /*or = st->buffer[ 3 * ( y * st->width + x ) + 0 ];
163 og = st->buffer[ 3 * ( y * st->width + x ) + 1 ];
164 ob = st->buffer[ 3 * ( y * st->width + x ) + 2 ];*/
166 c = st->buffer[ y * st->width + x ];
167 point2rgb( st->depth, c, &or, &og, &ob );
168 point2rgb( st->depth, myc, &r, &g, &b );
170 nr = or + (r - or) * a;
171 ng = og + (g - og) * a;
172 nb = ob + (b - ob) * a;
174 /*st->buffer[ 3 * ( y * st->width + x ) + 0 ] = nr;
175 st->buffer[ 3 * ( y * st->width + x ) + 1 ] = ng;
176 st->buffer[ 3 * ( y * st->width + x ) + 2 ] = nb;*/
177 c = rgb2point(st->depth, nr, ng, nb);
178 st->buffer[ y * st->width + x ] = c;
180 XPutPixel( st->buf, x, y, c );
186 void print_color ( struct state* st, pixel_t color ) {
188 point2rgb(st->depth, color, &r, &g, &b);
189 printf( "%d %d %d\n", r, g, b);
195 #define plot_(X,Y,D) do{ \
196 _dla_plot(st, (X), (Y), color, (D) * alpha); }while(0)
199 void _dla_plot(struct state* st, int x, int y, pixel_t col, float br)
201 if ( ( x >= 0 && x < st->width ) && ( y >= 0 && y < st->height ) ) {
202 if ( br > 1.0f ) br = 1.0f;
203 draw_point( st, x, y, col, br );
207 #define ipart_(X) ((int)(X))
208 #define round_(X) ((int)(((float)(X))+0.5))
209 #define fpart_(X) (((float)(X))-(float)ipart_(X))
210 #define rfpart_(X) (1.0-fpart_(X))
213 void draw_line_antialias(
217 pixel_t color, float alpha )
219 float dx = (float)x2 - (float)x1;
220 float dy = (float)y2 - (float)y1;
235 /* hard clipping, because this routine has some problems with negative coordinates */
236 /* TODO: fix the alpha for that boundary cases. Using fabs() could solve? */
237 if ( ( x1 < 0 || x1 > st->width ) ||
238 ( x2 < 0 || x2 > st->width ) ||
239 ( y1 < 0 || y1 > st->height ) ||
240 ( y2 < 0 || y2 > st->height ) )
243 if ( fabs(dx) > fabs(dy) ) {
250 yend = y1 + gradient*(xend - x1);
251 xgap = rfpart_(x1 + 0.5);
253 ypxl1 = ipart_(yend);
254 plot_(xpxl1, ypxl1, rfpart_(yend)*xgap);
255 plot_(xpxl1, ypxl1+1, fpart_(yend)*xgap);
256 intery = yend + gradient;
259 yend = y2 + gradient*(xend - x2);
260 xgap = fpart_(x2+0.5);
262 ypxl2 = ipart_(yend);
263 plot_(xpxl2, ypxl2, rfpart_(yend) * xgap);
264 plot_(xpxl2, ypxl2 + 1, fpart_(yend) * xgap);
266 /*if ( rfpart_(yend) * xgap < 0 || fpart_(yend) * xgap < 0)
267 printf("%f %f\n", rfpart_(yend) * xgap, fpart_(yend) * xgap);*/
268 for(x=xpxl1+1; x <= (xpxl2-1); x++) {
269 plot_(x, ipart_(intery), rfpart_(intery));
270 plot_(x, ipart_(intery) + 1, fpart_(intery));
271 /*if ( rfpart_(intery) < 0 || fpart_(intery) < 0)
272 printf("%f %f\n", rfpart_(intery), fpart_(intery));*/
282 xend = x1 + gradient*(yend - y1);
283 ygap = rfpart_(y1 + 0.5);
285 xpxl1 = ipart_(xend);
286 plot_(xpxl1, ypxl1, rfpart_(xend)*ygap);
287 plot_(xpxl1, ypxl1+1, fpart_(xend)*ygap);
288 interx = xend + gradient;
291 xend = x2 + gradient*(yend - y2);
292 ygap = fpart_(y2+0.5);
294 xpxl2 = ipart_(xend);
295 plot_(xpxl2, ypxl2, rfpart_(xend) * ygap);
296 plot_(xpxl2, ypxl2 + 1, fpart_(xend) * ygap);
298 for(y=ypxl1+1; y <= (ypxl2-1); y++) {
299 plot_(ipart_(interx), y, rfpart_(interx));
300 plot_(ipart_(interx) + 1, y, fpart_(interx));
314 void draw_line ( struct state* st, int x0, int y0, int x1, int y1, int color, float a ) {
324 steep = abs ( y1 - y0 ) > abs ( x1 - x0 );
325 if ( steep ) { swap(x0,y0); swap(x1,y1); }
326 if ( x0 > x1 ) { swap(x0,x1); swap(y0,y1); }
331 ystep = y0 < y1 ? 1 : -1;
332 if ( a > 1.0f ) a = 1.0f;
334 for ( x = x0; x < x1; x++ ) {
336 if ( ( y >= 0 && y < st->width ) && ( x >= 0 && x < st->height ) )
337 draw_point( st, y, x, color, a );
339 if ( ( x >= 0 && x < st->width ) && ( y >= 0 && y < st->height ) )
340 draw_point( st, x, y, color, a );
343 if ( ( error << 1 ) > deltax ) {
351 static void create_buffers ( struct state* st, Display* display, Screen* screen, Window window, GC gc ) {
353 XWindowAttributes xgwa;
354 XGetWindowAttributes( display, window, &xgwa );
356 /* Initialize the pixmap */
357 if ( st->buf != NULL ) XFreePixmap( display, st->pix );
359 XSetForeground( display, gc, st->colors[BLACK] );
360 st->pix = XCreatePixmap( display, window, st->width, st->height,
362 XFillRectangle( display, st->pix, gc, 0, 0, st->width, st->height);
364 /* Initialize the bitmap */
365 if ( st->buf != NULL ) XDestroyImage ( st->buf );
366 st->buf = XGetImage( display, st->pix, 0, 0, st->width, st->height, visual_depth(screen, st->visual), ZPixmap );
367 st->buffer = (pixel_t*) calloc(sizeof(pixel_t), st->width * st->height);
369 for ( i = 0; i < st->width * st->height; ++i ) st->buffer[i] = st->colors[BLACK];*/
372 static void init_particle ( particle_t* p, float dx, float dy, float direction, int color, int max_age ) {
373 float max_initial_velocity = 2.0f;
378 p->vx = max_initial_velocity * cos(direction);
379 p->vy = max_initial_velocity * sin(direction);
381 p->age = random() % max_age;
386 static void clamp ( int* value, int l, int h ) {
387 if ( *value < l ) *value = l;
388 if ( *value > h ) *value = h;
391 static pixel_t next_color ( struct state* st, pixel_t current ) {
394 point2rgb(st->depth, current, &r, &g, &b);
395 r += random() % 5 - 2;
396 g += random() % 5 - 2;
397 b += random() % 5 - 2;
402 return rgb2point( st->depth, r, g, b );
406 static void create_particles ( struct state* st ) {
411 for ( i = 0; i < st->particles_number; i++ ) {
412 emitx = ( st->ring_radius * sinf( M_PI * 2 * ( (float) i / st->particles_number ) ) );
413 emity = ( st->ring_radius * cosf( M_PI * 2 * ( (float) i / st->particles_number ) ) );
414 direction = (M_PI * i) / st->particles_number;
416 if ( st->epoch == WHITE && st->color )
417 st->colors[WHITE] = next_color(st, st->colors[WHITE]);
419 init_particle(st->particles + i, emitx, emity, direction, st->colors[WHITE], st->max_age);
424 /* randomly move one particle and draw it */
425 static void move ( particle_t* p, struct state * st ) {
426 int w = st->width / 2;
427 int h = st->height / 2;
434 p->vx += frand1() * st->curliness * max_dv;
435 p->vy += frand1() * st->curliness * max_dv;
439 draw_line_antialias( st,
440 w+p->xx, h+p->yy, w+p->x, h+p->y, p->color, 0.15 );
441 draw_line_antialias( st,
442 w-p->xx, h+p->yy, w-p->x, h+p->y, p->color, 0.15 );
444 draw_line( st, w+p->xx, h+p->yy, w+p->x, h+p->y, p->color, 0.15 );
445 draw_line( st, w-p->xx, h+p->yy, w-p->x, h+p->y, p->color, 0.15 );
449 /* if this is too old, die and reborn */
450 if ( p->age > st->max_age ) {
451 float dir = frand1() * 2 * M_PI;
452 p->x = st->ring_radius * sin(dir);
453 p->y = st->ring_radius * cos(dir);
454 p->xx = p->yy = p->vx = p->vy = 0;
457 if ( st->epoch == WHITE && st->color )
458 st->colors[WHITE] = next_color(st, st->colors[WHITE] );
460 p->color = st->colors[st->epoch];
467 /* Initialize Everything */
468 static void* binaryring_init ( Display* display, Window window ) {
469 XWindowAttributes xgwa;
471 struct state *st = ( struct state* ) calloc ( 1, sizeof( *st ) );
473 XGetWindowAttributes( display, window, &xgwa );
476 st->display = display;
478 st->particles_number = (get_integer_resource(st->display, "particles_number", "Integer"));
479 st->growth_delay = (get_integer_resource(st->display, "growth_delay", "Integer"));
480 st->ring_radius = (get_integer_resource(st->display, "ring_radius", "Integer"));
481 st->max_age = (get_integer_resource(st->display, "max_age", "Integer"));
482 st->color = get_boolean_resource(st->display, "color", "Boolean");
483 st->height = xgwa.height;
484 st->width = xgwa.width;
485 st->visual = xgwa.visual;
489 st->depth = visual_depth(xgwa.screen, st->visual);
490 st->colors[0] = rgb2point(st->depth, 0, 0, 0);
491 st->colors[1] = rgb2point(st->depth, 255, 255, 255);
493 /*describe_visual (stdout, xgwa.screen, xgwa.visual, False);*/
495 st->particles = malloc (st->particles_number * sizeof( particle_t ) );
496 create_particles ( st );
498 st->gc = XCreateGC( st->display, st->window, 0, &st->gcv );
499 create_buffers ( st, display, xgwa.screen, window, st->gc );
506 static unsigned long binaryring_draw ( Display* display, Window win, void *closure ) {
507 struct state *st = (struct state *) closure;
510 for ( i = 0; i < st->particles_number; i++ )
511 move( &(st->particles[i]), st );
513 /* draw the XImage in the Pixmap and the put the Pixmap on the screen */
514 XPutImage( display, st->pix, st->gc, st->buf, 0, 0, 0, 0, st->width, st->height);
515 XCopyArea( display, st->pix, win, st->gc, 0, 0, st->width, st->height, 0, 0 );
517 /* randomly switch ageColor periods */
518 if ( random() % 10000 > 9950 )
519 st->epoch = (st->epoch == WHITE) ? BLACK : WHITE;
521 return st->growth_delay;
526 static void binaryring_reshape ( Display* display, Window win, void *closure, unsigned int w, unsigned int h ) {
527 struct state *st = (struct state *) closure;
529 XWindowAttributes tmp;
530 XGetWindowAttributes(display, win, &tmp);
532 if ( tmp.height != st->height || tmp.width != st->width ) {
533 st->height = tmp.height;
534 st->width = tmp.width;
538 create_particles ( st );
540 create_buffers ( st, display, tmp.screen, win, st->gc );
545 /* if someone press a key switch the color */
546 static Bool binaryring_event ( Display* display, Window win, void *closure, XEvent* event ) {
547 struct state *st = (struct state *) closure;
549 if ( (*event).xany.type == KeyPress ) {
550 st->epoch = (st->epoch == WHITE) ? BLACK : WHITE;
557 /* delete everything */
558 static void binaryring_free ( Display* display, Window win, void *closure ) {
559 struct state *st = (struct state *) closure;
560 XWindowAttributes tmp;
561 XGetWindowAttributes(display, win, &tmp);
564 free( st->particles );
570 /* Default resources of the program */
571 static const char* binaryring_defaults [] = {
572 ".background: black",
573 ".foreground: white",
574 "*growth_delay: 10000",
575 "*particles_number: 5000",
579 "*ignoreRotation: True",
583 static XrmOptionDescRec binaryring_options [] = {
584 { "-particles-number", ".particles_number", XrmoptionSepArg, 0 },
585 { "-growth-delay", ".growth_delay", XrmoptionSepArg, 0 },
586 { "-ring-radius", ".ring_radius", XrmoptionSepArg, 0 },
587 { "-max-age", ".max_age", XrmoptionSepArg, 0 },
588 { "-color", ".color", XrmoptionNoArg, "True" },
589 { "-no-color", ".color", XrmoptionNoArg, "False" },
593 XSCREENSAVER_MODULE("BinaryRing", binaryring)