| Very interesting. This could well be the problem. I haven't looked
into this before. I do read events frequently and I seem to get alot
of events that don't fit any of the catagories that I'm looking for,
but I haven't gone so far as to see what they are. Anyway, I'm posting
some code for kicks. I have since sidestepped the problem by no
calling XCopyArea until the my last level of recursion. Thus I only
get around 50 calls per run versus 1000's before. I will have to see
about this expose business though.
Thanks alot.
John
P.S. Please excuse code sloppiness - still in testing phase.
/* This is an attempt to speed up the Mandelbrot drawing by recursively */
/* deviding the spaces into areas of all the same color to minimize the */
/* number of pixels to calculate. */
#include <stdio.h>
#include <math.h>
#include <time.h>
#ifdef VMS
# include <decw$include:Xlib.h>
# include <decw$include:Xutil.h>
#else
# include <X11/Xlib.h>
# include <X11/Xutil.h>
#endif
#include "mandel.h"
#define SCREEN_SIZE 730
#define REC_LIMIT 1
double xcorner = -2.0, ycorner = 2.0;
double gap = 4.0 / SCREEN_SIZE;
unsigned short current_side;
static XImage *mimage;
static int one_third, /* 1/3 the distance of the current block size */
two_thirds; /* 2 * one_third */
char iter_level = 0, color_changed[6][9][4];
/******************************************************************************/
int get_count( x, y )
/******************************************************************************/
/* calculate and return the count value for complex number at window */
/* coordinate (x, y) */
double x, y; /* window coordinate of pixel to calculate */
{
register count;
static double z_imag, z_real, z_imag2, z_real2;
z_imag2 = z_real2 = z_imag = z_real = 0;
for( count = 0; count < LIMIT; count++ )
{
if ( z_real2 + z_imag2 > 4.0 ) return count;
z_imag = 2 * z_real * z_imag + y;
z_real = z_real2 - z_imag2 + x;
z_real2 = z_real * z_real;
z_imag2 = z_imag * z_imag;
}
return count;
}
/******************************************************************************/
void calc_hline( xwin, ywin, npixels )
/******************************************************************************/
/* calculate and draw a horizontal line starting at window coord (xwin, ywin) */
/* and going for 'npixels' */
short xwin, ywin, /* upper-left hand window coord of current block */
npixels; /* number of pixels to calculate and draw */
{
register n, count;
double c_imag, c_real, z_imag, z_real, z_imag2, z_real2;
c_imag = ycorner - ywin*gap;
for ( n = 0; n < npixels; n++ )
{
c_real = xcorner + (xwin+n)*gap;
z_imag2 = z_real2 = z_imag = z_real = 0;
for( count = 0; count < LIMIT; count++ )
{
if ( z_real2 + z_imag2 > 4.0 ) break;
z_imag = 2 * z_real * z_imag + c_imag;
z_real = z_real2 - z_imag2 + c_real;
z_real2 = z_real * z_real;
z_imag2 = z_imag * z_imag;
}
XPutPixel( mimage, xwin+n, ywin, color_indices[count-1] );
}
}
/******************************************************************************/
void calc_vline( xwin, ywin, npixels )
/******************************************************************************/
/* calculate and draw a vertical line starting at window coord (xwin, ywin) */
/* and going for 'npixels' */
short xwin, ywin, /* upper-left hand window coord of current block */
npixels; /* number of pixels to calculate and draw */
{
register n, count;
double c_imag, c_real, z_imag, z_real, z_imag2, z_real2;
c_real = xcorner + xwin*gap;
for ( n = 0; n < npixels; n++ )
{
c_imag = ycorner - (ywin+n)*gap;
z_imag2 = z_real2 = z_imag = z_real = 0;
for( count = 0; count < LIMIT; count++ )
{
if ( z_real2 + z_imag2 > 4.0 ) break;
z_imag = 2 * z_real * z_imag + c_imag;
z_real = z_real2 - z_imag2 + c_real;
z_real2 = z_real * z_real;
z_imag2 = z_imag * z_imag;
}
XPutPixel( mimage, xwin, ywin+n, color_indices[count-1] );
}
}
/******************************************************************************/
void cut_it_up( x, y, side )
/******************************************************************************/
/* divide the block whose upper-left window coord. is (x, y), into a 3 x 3 */
/* matrix of smaller blocks each of side length 'side / 3' */
short x, y, side;
{
/* calculate and draw horizontal line 1/3 the way down y */
calc_hline( x+1, y+one_third, side-1 );
/* calculate and draw horizontal line 2/3 the way down y */
calc_hline( x+1, y+two_thirds, side-1 );
/* calculate and draw vertical line 1/3 the way along x */
calc_vline( x+one_third, y+1, one_third-1 );
calc_vline( x+one_third, y+one_third+1, one_third-1 );
calc_vline( x+one_third, y+two_thirds+1, one_third-1 );
/* calculate and draw vertical line 2/3 the way along x */
calc_vline( x+two_thirds, y+1, one_third-1 );
calc_vline( x+two_thirds, y+one_third+1, one_third-1 );
calc_vline( x+two_thirds, y+two_thirds+1, one_third-1 );
/* last thing has been put in the image so update the pixmap */
XPutImage( main_display, main_pixmap, main_gc, mimage,
x, y, x, y, side, side);
/*
XCopyArea( main_display, main_pixmap, main_window, main_gc,
x, y, side, side, x, y );
*/
}
/******************************************************************************/
void check_hline( x, y, npixels, flags )
/******************************************************************************/
/* check a horizontal line of pixels and return flags indication if the */
/* color changed in any of its three thirds */
short x, y, /* starting coordinates */
npixels; /* number of pixels to check; */
char *flags; /* pointer to a set of flags indicating color change */
{
char color_changed;
unsigned long color, last_color;
register i;
color_changed = FALSE;
last_color = XGetPixel( mimage, x, y );
for( i = 1; i < npixels; i++ )
{
if( (color = XGetPixel( mimage, x+i, y)) != last_color )
color_changed = TRUE;
if( i == one_third )
{
flags[0] = color_changed;
color_changed = FALSE;
}
if( i == two_thirds )
{
flags[1] = color_changed;
color_changed = FALSE;
}
last_color = color;
}
flags[2] = color_changed;
}
/******************************************************************************/
void check_vline( x, y, npixels, flags )
/******************************************************************************/
/* check a vertical line of pixels and return flags indication if the */
/* color changed in any of its three thirds */
short x, y, /* starting coordinates */
npixels; /* number of pixels to check; */
char *flags; /* pointer to a set of flags indicating color change */
{
char color_changed;
unsigned long color, last_color;
register i;
color_changed = FALSE;
last_color = XGetPixel( mimage, x, y );
for( i = 1; i < npixels; i++ )
{
if( (color = XGetPixel( mimage, x, y+i)) != last_color )
color_changed = TRUE;
if( i == one_third )
{
flags[0] = color_changed;
color_changed = FALSE;
}
if( i == two_thirds )
{
flags[1] = color_changed;
color_changed = FALSE;
}
last_color = color;
}
flags[2] = color_changed;
}
/******************************************************************************/
void update_flags( x, y, side )
/******************************************************************************/
/* this routine check the lines that make the exterior of the current block */
/* who's upper right hand window coordinate is (x,y); for each line it */
/* returns flags indicating if and where it changed color */
short x, y, /* current position in the window */
side; /* number of pixels on a side of the current block */
{
char flags[3];
/* check the horizontal lines */
check_hline( x, y, side, flags ); /* top side */
color_changed[iter_level][0][0] = flags[0];
color_changed[iter_level][3][0] = flags[1];
color_changed[iter_level][6][0] = flags[2];
check_hline( x, y+one_third, side, flags ); /* first third */
color_changed[iter_level][0][2] = color_changed[iter_level][1][0] = flags[0];
color_changed[iter_level][3][2] = color_changed[iter_level][4][0] = flags[1];
color_changed[iter_level][6][2] = color_changed[iter_level][7][0] = flags[2];
check_hline( x, y+two_thirds, side, flags ); /* second third */
color_changed[iter_level][1][2] = color_changed[iter_level][2][0] = flags[0];
color_changed[iter_level][4][2] = color_changed[iter_level][5][0] = flags[1];
color_changed[iter_level][7][2] = color_changed[iter_level][8][0] = flags[2];
check_hline( x, y+side, side, flags ); /* bottom side */
color_changed[iter_level][2][2] = flags[0];
color_changed[iter_level][5][2] = flags[1];
color_changed[iter_level][8][2] = flags[2];
/* check the virtical lines */
check_vline( x, y, side, flags ); /* left side */
color_changed[iter_level][0][3] = flags[0];
color_changed[iter_level][1][3] = flags[1];
color_changed[iter_level][2][3] = flags[2];
check_vline( x+one_third, y, side, flags ); /* first third */
color_changed[iter_level][0][1] = color_changed[iter_level][3][3] = flags[0];
color_changed[iter_level][1][1] = color_changed[iter_level][4][3] = flags[1];
color_changed[iter_level][2][1] = color_changed[iter_level][5][3] = flags[2];
check_vline( x+two_thirds, y, side, flags ); /* second third */
color_changed[iter_level][3][1] = color_changed[iter_level][6][3] = flags[0];
color_changed[iter_level][4][1] = color_changed[iter_level][7][3] = flags[1];
color_changed[iter_level][5][1] = color_changed[iter_level][8][3] = flags[2];
check_vline( x+side, y, side, flags ); /* right side */
color_changed[iter_level][6][1] = flags[0];
color_changed[iter_level][7][1] = flags[1];
color_changed[iter_level][8][1] = flags[2];
}
/******************************************************************************/
void fill_by_ones( x, y )
/******************************************************************************/
/* This routine is called when the side of the current block that is being */
/* calculated is 3, thus making it necessary to fill it in pixel by pixel */
short x, y;
{
register i, j;
int count;
/* since the outside is already done we only have to fill in the middle four */
/* pixels */
if( (count = get_count( xcorner+(x+1)*gap, ycorner-(y+1)*gap )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, x+1, y+1 );
}
if( (count = get_count( xcorner+(x+2)*gap, ycorner-(y+1)*gap )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, x+2, y+1 );
}
if( (count = get_count( xcorner+(x+1)*gap, ycorner-(y+2)*gap )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, x+1, y+2 );
}
if( (count = get_count( xcorner+(x+2)*gap, ycorner-(y+2)*gap )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, x+2, y+2 );
}
}
/******************************************************************************/
void check_blocks( x, y, side )
/******************************************************************************/
/* this is the main engine; for the current block whose upper-left hand */
/* window coordinte is (x, y) and length of side is 'side', check to see if */
/* all the walls of all 9 interior smaller blocks are of the same color */
/* if they are then fill in the particular block with that color and move on */
/* to the next; else cut that block up and start again */
short x, y, side;
{
register i, j, block_number;
short newside, newy;
unsigned long color;
newside = side / 3;
if ( newside > 1 )
{
block_number = 0;
for ( i = 0; i < 3; i++ )
{
newy = y;
for ( j = 0; j < 3; j++, block_number++ )
{
if( !color_changed[iter_level][block_number][0] &&
!color_changed[iter_level][block_number][1] &&
!color_changed[iter_level][block_number][2] &&
!color_changed[iter_level][block_number][3] )
{
if( (color = XGetPixel( mimage, x, newy )) != 0 )
{
XSetForeground( main_display, main_gc, color );
XFillRectangle( main_display, main_pixmap, main_gc,
x+1, newy+1, newside-1, newside-1 );
}
if( iter_level <= 1 )
XCopyArea( main_display, main_pixmap, main_window, main_gc,
x, newy, newside, newside, x, newy );
}
else if( newside != 3 )
{
iter_level++;
one_third = newside / 3;
two_thirds = 2 * one_third;
cut_it_up( x, newy, newside );
update_flags( x, newy, newside );
check_blocks( x, newy, newside );
if( iter_level == 1 )
XCopyArea( main_display, main_pixmap, main_window, main_gc,
x, newy, newside, newside, x, newy );
}
else
fill_by_ones( x, newy );
newy += newside;
}
x += newside;
}
}
iter_level--;
}
/******************************************************************************/
void createWindow( )
/******************************************************************************/
{
/* Open the display */
if ( !(main_display = XOpenDisplay( 0 )) ){
printf( "Can't open display\n" );
exit( 1 );
}
/* Create the mask that tells what events to look for in the window */
main_xswa.save_under = TRUE;
/* set the background and color */
main_xswa.background_pixel = BlackPixel( main_display,
DefaultScreen( main_display ) );
/* create the screen */
main_screen = XDefaultScreenOfDisplay( main_display );
/* create the window and give it a name */
main_window =
XCreateWindow( main_display, /* display id */
XRootWindowOfScreen( main_screen ), /* window id*/
50, 0, /* position of upper left hand corner */
SCREEN_SIZE, SCREEN_SIZE, /* width and height in pixels */
0, /* width of border in pixels */
XDefaultDepthOfScreen( main_screen ), /* bits per pixel */
InputOutput, /* type if interaction */
XDefaultVisualOfScreen( main_screen ), /* visual struct */
CWBackPixel | CWSaveUnder, /* attb mask */
&main_xswa); /* attributes */
XStoreName( main_display, main_window, "Recursive Mandel " );
main_gc = XCreateGC( main_display, main_window, 0, 0 );
XMapWindow( main_display, main_window );
}
/******************************************************************************/
/******************************************************************************/
main(argc, argv)
int argc;
char *argv[];
/******************************************************************************/
/******************************************************************************/
{
int count;
time_t time1, time2, tp;
createWindow( );
if ( argc == 1 )
XSynchronize( main_display, 1 );
initColors( );
main_pixmap = XCreatePixmap( main_display, main_window,
SCREEN_SIZE, SCREEN_SIZE,
XDefaultDepthOfScreen( main_screen ) );
XSetForeground( main_display, main_gc, BlackPixelOfScreen( main_screen ) );
XFillRectangle( main_display, main_pixmap, main_gc,
0, 0, SCREEN_SIZE, SCREEN_SIZE );
mimage = XGetImage( main_display, main_pixmap,
0, 0, SCREEN_SIZE, SCREEN_SIZE, AllPlanes, ZPixmap );
/* take a time stamp */
time1 = time( &tp );
printf( "%s", ctime( &tp ) );
/* prime the pump by calculating the for corner points */
if( (count = get_count( -2.0, 2.0 )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, 0, 0 );
XPutPixel( mimage, 0, 0, color_indices[count-1] );
}
if( (count = get_count( 2.0, 2.0 )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, SCREEN_SIZE-1, 0 );
XPutPixel( mimage, SCREEN_SIZE-1, 0, color_indices[count-1] );
}
if( (count = get_count( -2.0, -2.0 )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, 0, SCREEN_SIZE-1 );
XPutPixel( mimage, 0, SCREEN_SIZE-1, color_indices[count-1] );
}
if( (count = get_count( 2.0, -2.0 )) != LIMIT )
{
XSetForeground( main_display, main_gc, color_indices[count-1] );
XDrawPoint( main_display, main_pixmap, main_gc, SCREEN_SIZE-1, SCREEN_SIZE-1 );
XPutPixel( mimage, SCREEN_SIZE-1, SCREEN_SIZE-1, color_indices[count-1] );
}
one_third = (SCREEN_SIZE-1) / 3;
two_thirds = 2 * one_third;
/* upper left to upper right */
calc_hline( 1, 0, SCREEN_SIZE-2 );
/* upper left to lower left */
calc_vline( 0, 1, SCREEN_SIZE-2 );
/* upper right to lower right */
calc_vline( SCREEN_SIZE-1, 1, SCREEN_SIZE-2 );
/* lower left to lower right */
calc_hline( 1, SCREEN_SIZE-1, SCREEN_SIZE-2 );
cut_it_up( 0, 0, SCREEN_SIZE );
update_flags( 0, 0, SCREEN_SIZE );
check_blocks( 0, 0, SCREEN_SIZE-1 );
XCopyArea( main_display, main_pixmap, main_window, main_gc,
SCREEN_SIZE-1, 0, 1, SCREEN_SIZE, SCREEN_SIZE-1, 0 );
XCopyArea( main_display, main_pixmap, main_window, main_gc,
0, SCREEN_SIZE-1, SCREEN_SIZE, 1, 0, SCREEN_SIZE-1);
time2 = time( &tp );
printf( "%s", ctime( &tp ) );
printf( "#Mins: %f\n", difftime( time2, time1 ) / 60.0 );
XFlush( main_display );
printf( "Hit return to end:\007\n" );
getchar( );
XFree( mimage );
WritePixmapFile( main_display, "wholeset.bit", main_pixmap, 0, 0 );
}
|