more flood speedups

This commit is contained in:
John Cupitt 2009-12-30 08:08:26 +00:00
parent 1b5dd8524a
commit 3d959dbe3b

View File

@ -187,27 +187,12 @@ buffer_add( Buffer *buf, Flood *flood, int x1, int x2, int y, int dir )
/* Is p "connected"? ie. is equal to or not equal to flood->edge, depending on /* Is p "connected"? ie. is equal to or not equal to flood->edge, depending on
* whether we are flooding to the edge boundary or flooding edge-coloured * whether we are flooding to the edge boundary or flooding edge-coloured
* pixels. * pixels.
*
* If test and mark are different images, we also need to check ink to make
* sure we haven't painted this pixel before. Otherwise we can get stuck in
* loops.
*/ */
static inline gboolean static inline gboolean
flood_connected( Flood *flood, PEL *tp, PEL *mp ) flood_connected( Flood *flood, PEL *tp )
{ {
int j; int j;
if( flood->test != flood->mark ) {
for( j = 0; j < flood->msize; j++ )
if( mp[j] != flood->ink[j] )
break;
if( j == flood->msize )
/* We've painted this before, can't be connected now.
*/
return( FALSE );
}
for( j = 0; j < flood->tsize; j++ ) for( j = 0; j < flood->tsize; j++ )
if( tp[j] != flood->edge[j] ) if( tp[j] != flood->edge[j] )
break; break;
@ -217,6 +202,20 @@ flood_connected( Flood *flood, PEL *tp, PEL *mp )
return( flood->equal ^ (j < flood->tsize) ); return( flood->equal ^ (j < flood->tsize) );
} }
/* Is p painted?
*/
static inline gboolean
flood_painted( Flood *flood, PEL *mp )
{
int j;
for( j = 0; j < flood->msize; j++ )
if( mp[j] != flood->ink[j] )
break;
return( j == flood->msize );
}
/* Faster than memcpy for n < about 20. /* Faster than memcpy for n < about 20.
*/ */
static inline void static inline void
@ -229,7 +228,7 @@ flood_paint( Flood *flood, PEL *q )
} }
/* Fill left and right, return the endpoints. The start point (x, y) must be /* Fill left and right, return the endpoints. The start point (x, y) must be
* connected. * connected and unpainted.
*/ */
static void static void
flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 ) flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 )
@ -239,33 +238,43 @@ flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 )
PEL *tp; PEL *tp;
PEL *mp; PEL *mp;
int i; int i;
int j;
g_assert( flood_connected( flood, g_assert( flood_connected( flood,
(PEL *) IM_IMAGE_ADDR( flood->test, x, y ), (PEL *) IM_IMAGE_ADDR( flood->test, x, y ) ) );
g_assert( !flood_painted( flood,
(PEL *) IM_IMAGE_ADDR( flood->mark, x, y ) ) ); (PEL *) IM_IMAGE_ADDR( flood->mark, x, y ) ) );
/* Fill this pixel and to the right. /* Search to the right for the first non-connected pixel. If the start
* pixel is unpainted, we know all the intervening pixels must be
* unpainted too.
*/ */
tp = (PEL *) IM_IMAGE_ADDR( flood->test, x, y ); tp = (PEL *) IM_IMAGE_ADDR( flood->test, x, y );
mp = (PEL *) IM_IMAGE_ADDR( flood->mark, x, y ); for( i = x; i < width; i++ ) {
for( i = x; i < width && flood_connected( flood, tp, mp ); i++ ) { if( !flood_connected( flood, tp ) )
flood_paint( flood, mp ); break;
tp += flood->tsize; tp += flood->tsize;
mp += flood->msize;
} }
*x2 = i - 1; *x2 = i - 1;
/* Fill to the left. /* Search left.
*/ */
tp = (PEL *) IM_IMAGE_ADDR( flood->test, x - 1, y ); tp = (PEL *) IM_IMAGE_ADDR( flood->test, x - 1, y );
mp = (PEL *) IM_IMAGE_ADDR( flood->mark, x - 1, y ); for( i = x - 1; i > 0; i-- ) {
for( i = x - 1; i > 0 && flood_connected( flood, tp, mp ); i-- ) { if( !flood_connected( flood, tp ) )
flood_paint( flood, mp ); break;
tp -= flood->tsize; tp -= flood->tsize;
mp -= flood->msize;
} }
*x1 = i + 1; *x1 = i + 1;
/* Paint the range we discovered.
*/
mp = (PEL *) IM_IMAGE_ADDR( flood->mark, x, y );
for( i = *x1; i <= *x2; i++ ) {
flood_paint( flood, mp );
mp += flood->msize;
}
if( flood->dout ) { if( flood->dout ) {
flood->left = IM_MIN( flood->left, *x1 ); flood->left = IM_MIN( flood->left, *x1 );
flood->right = IM_MAX( flood->right, *x2 ); flood->right = IM_MAX( flood->right, *x2 );
@ -285,18 +294,29 @@ flood_scanline( Flood *flood, int x, int y, int *x1, int *x2 )
static void static void
flood_around( Flood *flood, Scan *scan ) flood_around( Flood *flood, Scan *scan )
{ {
PEL *tp;
int x; int x;
g_assert( scan->dir == 1 || scan->dir == -1 ); g_assert( scan->dir == 1 || scan->dir == -1 );
tp = (PEL *) IM_IMAGE_ADDR( flood->test, scan->x1, scan->y );
for( x = scan->x1; x <= scan->x2; x++ ) { for( x = scan->x1; x <= scan->x2; x++ ) {
PEL *tp = (PEL *) IM_IMAGE_ADDR( flood->test, x, scan->y ); if( flood_connected( flood, tp ) ) {
PEL *mp = (PEL *) IM_IMAGE_ADDR( flood->mark, x, scan->y );
if( flood_connected( flood, tp, mp ) ) {
int x1a; int x1a;
int x2a; int x2a;
/* If mark and test are different images, we also need
* to check for painted. Otherwise we can get stuck in
* connected loops.
*/
if( flood->mark != flood->test ) {
PEL *mp = (PEL *) IM_IMAGE_ADDR(
flood->mark, x, scan->y );
if( flood_painted( flood, mp ) )
continue;
}
flood_scanline( flood, x, scan->y, &x1a, &x2a ); flood_scanline( flood, x, scan->y, &x1a, &x2a );
/* Our new scanline can have up to three more /* Our new scanline can have up to three more
@ -316,7 +336,10 @@ flood_around( Flood *flood, Scan *scan )
scan->dir ); scan->dir );
x = x2a; x = x2a;
tp = (PEL *) IM_IMAGE_ADDR( flood->test, x, scan->y );
} }
tp += flood->tsize;
} }
} }
@ -341,8 +364,7 @@ flood_all( Flood *flood, int x, int y )
/* Test start pixel ... nothing to do? /* Test start pixel ... nothing to do?
*/ */
if( flood_connected( flood, if( flood_connected( flood,
(PEL *) IM_IMAGE_ADDR( flood->test, x, y ), (PEL *) IM_IMAGE_ADDR( flood->test, x, y ) ) ) {
(PEL *) IM_IMAGE_ADDR( flood->mark, x, y ) ) ) {
int x1, x2; int x1, x2;
flood_scanline( flood, x, y, &x1, &x2 ); flood_scanline( flood, x, y, &x1, &x2 );