jef@well.sf.ca.us (Jef Poskanzer) (04/21/91)
In the referenced message, rsbx@cbmvax.commodore.com (Raymond S. Brand) wrote: }The request was for a way to rotate a bitmap 90 degrees without having to do }a readpixel/writepixel for each pixel in the area to rotate. What follows is }a shar file with the source (Amiga but you can understand it anyway :-) to 2 }rotate functions and 2 test programs. Appended is a version for Suns using raw pixrect calls. It's embedded in a screen-rot program of the same genre as meltdown and termite, but the rotation routine may be useful by itself. --- Jef Jef Poskanzer jef@well.sf.ca.us {apple, ucbvax, hplabs}!well!jef If you eat a live frog in the morning, nothing worse will happen to either of you for the rest of the day. /* ** sunrot - rot a Sun screen by rotating random squares ** ** Compile with: cc -O sunrot.c -lpixrect -s -o sunrot ** ** The rotation algorithm is similar to the one in "Smalltalk-80: The ** Language and Implementation", page 408. In particular, the mask ** refinement step is the same. However, the rest is different, simpler, ** doesn't flash white bars on the screen, and runs slightly faster (same ** number of blits but smaller area), at the cost of three off-screen ** temp areas instead of two. I consider this modified version fairly ** obvious, in case anyone is getting any stupid ideas about patenting ** it. The original version was non-obvious, but memory has gotten a ** lot cheaper since 1983. ** ** Copyright (C) 1991 by Jef Poskanzer. ** ** 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 software is provided "as is" without express or ** implied warranty. */ #include <stdio.h> #include <sys/types.h> #include <sys/timeb.h> #include <sys/file.h> #include <pixrect/pixrect_hs.h> #define PIX_AND ( PIX_SRC & PIX_DST ) #define PIX_OR ( PIX_SRC | PIX_DST ) Pixrect* my_pr_open(); void pr_rotatepow2square(); void main( argc, argv ) int argc; char* argv[]; { int argn, delay; struct timeb tb; Pixrect* disp_pr; int wid, hgt, maxpow2; int x, y, pow2, cw; char* fb; char* usage = "usage: %s [-fb <framebuffer>] [-delay <msec>]\n"; argn = 1; fb = "/dev/fb"; delay = 0; if ( argn < argc && argv[argn][0] == '-' ) { if ( strcmp( argv[argn], "-fb" ) == 0 || strcmp( argv[argn], "-f" ) == 0 ) { ++argn; fb = argv[argn]; } else if ( strcmp( argv[argn], "-delay" ) == 0 || strcmp( argv[argn], "-dela" ) == 0 || strcmp( argv[argn], "-del" ) == 0 || strcmp( argv[argn], "-de" ) == 0 || strcmp( argv[argn], "-d" ) == 0 ) { ++argn; delay = atoi( argv[argn] ); } else { fprintf( stderr, usage, argv[0] ); exit( 1 ); } ++argn; } if ( argn != argc ) { fprintf( stderr, usage, argv[0] ); exit( 1 ); } if ( ( disp_pr = my_pr_open( fb ) ) == (Pixrect*) 0 ) { fprintf( stderr, "%s: error opening display\n", argv[0] ); exit( 1 ); } wid = disp_pr->pr_size.x; hgt = disp_pr->pr_size.y; for ( maxpow2 = 1; ( 2 << maxpow2 ) <= wid && ( 2 << maxpow2 ) <= hgt; ++maxpow2 ) ; ftime( &tb ); srandom( (int) ( tb.time ^ tb.millitm ^ getpid( ) ) ); for ( ; ; ) { pow2 = random() % ( maxpow2 + 1 ); x = random() % ( wid - ( 1 << pow2 ) ); y = random() % ( hgt - ( 1 << pow2 ) ); cw = random() % 2; pr_rotatepow2square( disp_pr, x, y, pow2, cw ); if ( delay != 0 ) usleep( delay * 1000 ); } } Pixrect* my_pr_open( fb ) char* fb; { int fd; /* Test with open first, to avoid stupid error messages from pr_open(). */ if ( ( fd = open( fb, O_RDWR ) ) == -1 ) return (Pixrect*) 0; close( fd ); return pr_open( fb ); } static Pixrect* temp1 = (Pixrect*) 0; static Pixrect* temp2 = (Pixrect*) 0; static Pixrect* mask = (Pixrect*) 0; void pr_rotatepow2square( pr, x, y, pow2, cw ) Pixrect* pr; int x, y, pow2, cw; { int s, h, q, ts, th, tq; if ( pow2 < 2 ) return; s = 1 << pow2; h = s / 2; q = h / 2; /* Make sure that temps and mask are big enough and the right depth. */ if ( temp1 != (Pixrect*) 0 ) if ( temp1->pr_size.x < s || temp1->pr_size.y < s || temp1->pr_depth != pr->pr_depth ) { pr_destroy( temp1 ); temp1 = (Pixrect*) 0; pr_destroy( temp2 ); temp2 = (Pixrect*) 0; pr_destroy( mask ); mask = (Pixrect*) 0; } if ( temp1 == (Pixrect*) 0 ) { temp1 = mem_create( s, s, pr->pr_depth ); temp2 = mem_create( s, s, pr->pr_depth ); mask = mem_create( s, s, 1 ); } /* Initialize mask to the upper left quadrant. */ pr_rop( mask, 0, 0, s, s, PIX_CLR, (Pixrect*) 0, 0, 0 ); pr_rop( mask, 0, 0, h, h, PIX_SET, (Pixrect*) 0, 0, 0 ); for ( ts = s, th = ts / 2, tq = th / 2; pow2 > 0; --pow2, ts = th, th = tq, tq /= 2 ) { if ( cw ) pr_rop( temp1, 0, 0, s-th, s-th, PIX_SRC, pr, x, y+th ); else pr_rop( temp1, 0, 0, s-th, s-th, PIX_SRC, pr, x+th, y ); pr_rop( temp1, 0, 0, s, s, PIX_AND, mask, 0, 0 ); if ( cw ) pr_rop( temp2, th, 0, s-th, s-th, PIX_SRC, pr, x, y ); else pr_rop( temp2, th, 0, s-th, s-th, PIX_SRC, pr, x+th, y+th ); pr_rop( temp2, th, 0, s-th, s-th, PIX_AND, mask, 0, 0 ); pr_rop( temp1, th, 0, s-th, s-th, PIX_OR, temp2, th, 0 ); if ( cw ) pr_rop( temp2, th, th, s-th, s-th, PIX_SRC, pr, x+th, y ); else pr_rop( temp2, th, th, s-th, s-th, PIX_SRC, pr, x, y+th ); pr_rop( temp2, th, th, s-th, s-th, PIX_AND, mask, 0, 0 ); pr_rop( temp1, th, th, s-th, s-th, PIX_OR, temp2, th, th ); if ( cw ) pr_rop( temp2, 0, th, s-th, s-th, PIX_SRC, pr, x+th, y+th ); else pr_rop( temp2, 0, th, s-th, s-th, PIX_SRC, pr, x, y ); pr_rop( temp2, 0, th, s-th, s-th, PIX_AND, mask, 0, 0 ); pr_rop( temp1, 0, th, s-th, s-th, PIX_OR, temp2, 0, th ); /* And copy back to the screen. */ pr_rop( pr, x, y, s, s, PIX_SRC, temp1, 0, 0 ); /* Refine mask. */ pr_rop( mask, 0, 0, s-tq, s-tq, PIX_AND, mask, tq, tq ); pr_rop( mask, 0, th, s, s-th, PIX_OR, mask, 0, 0 ); pr_rop( mask, th, 0, s-th, s, PIX_OR, mask, 0, 0 ); } }