// File name: fill.C // original written by Ee-Chien Chang // rewritten by Ting-jen Yen #include #include #include #include "sparse_mask.h" // for class item #include "sparse_2.h" #include "tcpstream.h" #include "GLOBAL_VARIABLE.h" #include "display.h" extern unsigned long cols[256]; extern int byte_per_pixel; //----------------------------------------------- // F I L L //----------------------------------------------- // // A collection of routine to fill in a given memory // //----------------------------------------------- // // Example: // zoom ==1 // // level 0 1 2 3 4 // 2048 1024 512 256 128 // // Then the image is displayed at the resolution level 1. // // The st_row, en_row, st_col, en_col are in the co-ordinate // system at resolution level 1. // // // Example // the width of the window/image is 800, // the following with store the best resolution from level 1 onward // into Image, starting at location &Image[0]. // // // fill ( Image, 20, 511, // 10, 200, 1, 800 ); // //----------------------------------------------- inline int min ( int x, int y ) { return ( ( (x) > (y) ) ? (y) : (x) ); } inline int compute_color ( unsigned char * p ) { /* unsigned char tmp; tmp = ( p[0] & 0xe0 ); tmp |= ( p[1] & 0xe0 ) >> 3; tmp |= ( p[2] & 0xc0 ) >> 6; return tmp; */ return cols[(p[0] & 0xe0) | ((p[1] & 0xe0) >> 3) | (p[2] >> 6)]; } int fill_direct ( unsigned char * buf, int st_row, int en_row, int st_col, int en_col, int level, int scanline ) { //cout << "FILL DIRET " << "st_row en_row " << st_row << " " << en_row << endl; //cout << "FILL DIRET " << "st_col en_col " << st_col << " " << en_col << endl; //cout << "FILL DIRET " << "scanline level" << scanline<<" " << level << endl; if ( (st_row < 0 ) || (st_col < 0 ) || (st_row > en_row) || (st_col > en_col) || (en_row >=( C[level].get_non_padding_height() ) ) || (en_col >=( C[level].get_non_padding_width() ) ) ) cout << "FILL_DIRECT ERROR ..... OUT OF BOUND " << st_row << " " << en_row << " " << st_col << " " << en_col << endl; for (int i= st_row; i<= en_row; i++) { for (int j= st_col; j<= en_col; j++) { //---------- determine the color at level == curr_zoom // location (x,y) // int y = i ; int x = j ; int tmp_level = level ; int done=0; while (!done ) { if ( tmp_level >= ( HEADER.NOS_LEVEL ) ) { done = 1; } else if ( T[ tmp_level ] [y/2][x/2] ) { done = 1; } if (done) { int loc; if (byte_per_pixel == 3) { loc = (i-st_row) * scanline + (j-st_col)*4; buf [loc + 1] = C[ tmp_level].fs(y,x).b ; buf [loc + 2] = C[ tmp_level].fs(y,x).g ; buf [loc + 3] = C[ tmp_level].fs(y,x).r ; } else { loc = (i-st_row) * scanline + (j-st_col); buf [ loc ] = compute_color(&C[ tmp_level].fs(y,x).r ); } } else { tmp_level ++ ; x = x>>1; y=y>>1; } } } } } //----------------------------------------------------------- //----------------------------------------------------------- int fill_ultra_fast ( unsigned char * buf, int st_row, int en_row, int st_col, int en_col, int level, int scanline ) { int diff = HEADER.NOS_LEVEL - level ; int expansion = 1 << ( diff ); #ifdef BOUND_CHECK //------------- B O U N D C H E C K ------------- if (((en_row >> diff) >= HEADER.LOWEST_RESOLUTION_HEIGHT) || (st_row <0 ) ) { cout << " ERROR ***IMPOSSIBLE : fill_ultra_fast "<< en_row << endl; en_row = ( HEADER.LOWEST_RESOLUTION_HEIGHT << diff ) -1; } if (((en_col>> diff) >= HEADER.LOWEST_RESOLUTION_WIDTH) || (st_col <0 ) ) { cout << " ERROR ***IMPOSSIBLE : fill_ultra_fast "<< en_col << endl; en_col = ( HEADER.LOWEST_RESOLUTION_WIDTH << diff ) -1; } #endif // ------ t r i v a l i m p l e m e n t a i o n // // for (int i = st_row; i<= en_row; i++) // for (int j = st_col; j<= en_col; j++) // buf[ (i-st_row) *scanline + (j-st_col) ] = // compute_color ( &C[HEADER.NOS_LEVEL].fs(i>>diff,j>>diff).r); //------------------------------------------------------------------------ int sst_row = ( ( st_row >> diff ) + 1 )<< diff; int een_row = ( ( en_row >> diff ) )<< diff; int rept = en_col - st_col + 1; int flag =1; if (byte_per_pixel == 3) { rept *= 4; } if ( sst_row > en_row ) { sst_row = en_row+1; flag = 0; } // cout << "sst_row " << sst_row << " een_row " << een_row // << " st_row " << st_row << " en_row " << en_row << endl; //----------- t a k e c a r e o f b e g i n i n g for (int j = st_col, j0 = 0; j<= en_col; j++, j0++) { if (byte_per_pixel == 3) { buf[ 4 * j0 + 1] = C[HEADER.NOS_LEVEL].fs(st_row>>diff, j>>diff).b; buf[ 4 * j0 + 2] = C[HEADER.NOS_LEVEL].fs(st_row>>diff, j>>diff).g; buf[ 4 * j0 + 3] = C[HEADER.NOS_LEVEL].fs(st_row>>diff, j>>diff).r; } else { buf[ j0 ] = compute_color(&C[HEADER.NOS_LEVEL].fs(st_row>>diff, j>>diff).r); } } for (int ii= st_row+1 ; ii< sst_row; ii++) bcopy ( &buf[0], &buf[(ii-st_row)*scanline ], rept ); //----------- main body ---------------------------------------// for (int i = sst_row; i< een_row; i += (1<>diff, j>>diff).b ; buf [loc + 2] = C[HEADER.NOS_LEVEL].fs(i>>diff, j>>diff).g ; buf [loc + 3] = C[HEADER.NOS_LEVEL].fs(i>>diff, j>>diff).r ; } else { loc = (i-st_row)*scanline + (j-st_col); buf [loc] = compute_color (&C[HEADER.NOS_LEVEL].fs(i>>diff, j>>diff).r); } } for (int ii= 1 ; ii< (1<>diff, j>>diff).b; buf [loc + 2] = C[HEADER.NOS_LEVEL].fs(een_row>>diff, j>>diff).g; buf [loc + 3] = C[HEADER.NOS_LEVEL].fs(een_row>>diff, j>>diff).r; } else { loc = (een_row-st_row)*scanline + (j-st_col); buf[loc] = compute_color (&C[HEADER.NOS_LEVEL].fs(een_row>>diff, j>>diff).r); } } for (int ii= 1 ; ii< (en_row-een_row+1) ; ii++) bcopy ( &buf[(een_row -st_row)*scanline], &buf[(een_row + ii -st_row)*scanline], rept ); } } //------------------------------------------------------------- // // T H E M O S T C O N F U S I N G , // I M P O R T A N T , // C O M P L I C A T E D R O U T I N E // I N T H I S P A C K A G E //------------------------------------------------------------- // By Ee-Chien Chang // // Example // // HEADER.NOS_LEVEL == 4 // // T[0] -------*****-------****---***--------*****--- // T[1] ----********-------************----*******--- // T[2] --**********--*---*************---*********-- // T[3] --*************---*************************** // ^ // curr_col // // output.... // // 442211100000332444200001110001133321100000233 // // That is not all... // Copy the above to differnt rows. will do it later.... // // // All the co-ordinate must be within BOUND // //------------------------------------------------------ // U N D E R C O N S T R U C T I O N // this routine could be further improve. // so far, it only take advantage on "column-wise" // Need to work on rowwise..... //------------------------------------------------------------ int fill_best ( unsigned char * buf, int st_row, int en_row, int st_col, int en_col, int level, int scanline ) { //cout << "FILL BEST " << "st_row en_row " << st_row << " " << en_row << endl; //cout << "FILL BEST " << "st_col en_col " << st_col << " " << en_col << endl; //cout << "FILL BEST " << "scanline level" << scanline<<" " << level << endl; //------------- B O U N D C H E C K ------------- #ifdef BOUND_CHECK if ( en_row >= C[level].get_non_padding_height() ) { cout << " ERROR ***IMPOSSIBLE : fill_best "<< en_row << endl; en_row = C[level].get_non_padding_height() -1; while (1) {} } if ( en_col >= C[level].get_non_padding_width() ) { cout << " ERROR ***IMPOSSIBLE : fill_best "<< en_col << endl; en_col = C[level].get_non_padding_width() -1; while (1) {} } if( (st_col > en_col ) || (st_row > en_row ) || (st_row < 0 ) || (en_row < 0 ) || (st_col < 0 ) || (en_col < 0 ) ) { cout << "ERROR.... fill best " << endl; exit(0); } #endif // curr[l] will point to the first element in SpaseMask that // intersect with st_col and en_col //--------------------------------------------- // // B I G M I S T A K E //-------------------------------------------- // The following two statement is FATALLY WRONG // // item * curr [HEADER.NOS_LEVEL -1]; // item * ttcurr [HEADER.NOS_LEVEL +1]; // // it seem the when the routine return, not only curr will be // disposed, it content (for eg. what curr[0] point to ) will // alway be disposed. .... (check book ) // // remember : A L W A Y S use pointers. //---------------------------------------------- // item ** curr = new (item *) [HEADER.NOS_LEVEL -1]; // item ** ttcurr = new (item *) [HEADER.NOS_LEVEL +1]; item ** curr = new (item *) [HEADER.NOS_LEVEL ]; item ** ttcurr = new (item *) [HEADER.NOS_LEVEL +2]; item ** tcurr; //--------------------------------------- // add dummy so that tcurr[-1] is well defined //-------------------------------------- tcurr = &ttcurr[1]; ttcurr [0] = 0; // tcurr[-1] = 0; tcurr[HEADER.NOS_LEVEL]=new item( 0, (HEADER.LOWEST_RESOLUTION_WIDTH+1)/2,0); // int prev_row [HEADER.NOS_LEVEL]; int prev_level [en_col - st_col + 1]; for (int i=0;i< HEADER.NOS_LEVEL; i++) { // prev_row[i]=0; tcurr[i]=0; } //--------------initialise ----------------// for (int l= 0; l< HEADER.NOS_LEVEL; l++) curr [l] = T[l][st_row>>(l+1-level)].first_occurance(st_col>>(l+1-level), en_col>>(l+1-level)); for (int curr_row = st_row; curr_row <= en_row; curr_row ++ ) { #ifdef FILL_DEBUG cout << "********* R O W " << curr_row << "*******" << endl; #endif //-------------------------------------------------------------- // c h e c k f o r s p e c i a l c a s e // w h e r e r o w n u m b e r i s o d d //-------------------------------------------------------------- int reuse_level = HEADER.NOS_LEVEL+1; if ( (curr_row %2 ) && ( curr_row != st_row ) ) { int tmp_row = curr_row ; for (int l=level; l> 1 ;} } else { //-------------------------------------------------------------- // To find curr[l], // try to reuse previous value. // T[-1]--------------------------------------------- // T[0] --------------------------------------------- // T[1] ----********-------************----*******--- // T[2] --**********--*---*************---*********-- // T[3] --*************---*************************** // T[4] ********************************************* // T[5] ********************************************* //--------------------------------------------------------------- int tmp_row = curr_row; reuse_level = HEADER.NOS_LEVEL+1; for (int l= level; l< HEADER.NOS_LEVEL; l++) { if (!(tmp_row % 2 )) { curr [l] = T[l][curr_row>>(l+1-level)].first_occurance ( st_col >> (l+1-level), en_col >> (l+1-level) ); tcurr[l] = curr[l]; tmp_row = tmp_row >>1; } else { for (int ll=l; llstart_from>>1) >tcurr[found]->end_at) ) ) { #ifdef FILL_DEBUG cout << "down" << found << endl; #endif //----------------------------------------------------- // suppose previous value of found is 2 // // T[1] -------------------************----*******--- // T[2] --**********--*---*************---*********-- // T[3] ************--*---*************************** // T[4] ********************************************* // ^ ^ // curr_col curr_col (updated) // updated value of found == 4 //---------------------------------------------------- int tmpmin=min(((tcurr[found]->end_at+1)<<(found+1-level))-1, en_col ); for (int i=curr_col; i<= tmpmin; i++) { prev_level [i-st_col] = found; } if (tmpmin != en_col) { do { tcurr[found] = tcurr[found]->next; found = found +1; } while ( (found < reuse_level) && ((tcurr[found]->end_at+1)<< (found+1-level)) == (tmpmin +1) ) ; } curr_col = tmpmin+1; if ( found >= reuse_level ) { #ifdef FILL_DEBUG cout << "reuse " << reuse_level << " curr_col " << curr_col << endl; #endif if (!tcurr[found-1]) {curr_col = en_col+1; } else {curr_col = min ( ( tcurr[found-1] -> start_from << (found-level) ), en_col+1); } found --; } #ifdef FILL_DEBUG cout << "down done " << endl; #endif } else { #ifdef FILL_DEBUG cout << "up" << found << endl; #endif //----------------------------------------------------- // suppose previous value of found is 2 // // T[0] -------***---------************----*******--- // T[1] -------***---------************----*******--- // T[2] --**********--*---*************---*********-- // T[3] ************--*---*************************** // T[4] ********************************************* // ^ ^ // curr_col curr_col (updated) // updated value of found == 1 ## N O T 0 ### //----------------------------------------------------- int tmpmin =min(tcurr[found-1]->start_from << (found-level), en_col+1 ); for (int i= curr_col; i< tmpmin ; i++) { prev_level [i-st_col]=found; } curr_col = tmpmin ; found = found -1; } } // for curr_col } // if curr_row is even for (int i=st_col; i<=en_col; i++) { int tmp = (curr_row - st_row) * scanline + (i - st_col); if (prev_level[ i-st_col ] >= reuse_level ) { if (byte_per_pixel == 3) { tmp += (3*(i-st_col)); bcopy(&buf[tmp+1 - scanline], &buf[tmp+1], 3); } else buf [ tmp ] = buf [ tmp -scanline ]; } else { int swift = prev_level[ i-st_col] -level ; if (byte_per_pixel == 3) { tmp += 3*(i-st_col); buf[tmp + 1] = C[prev_level[i-st_col] ].fs( curr_row >> swift, i >> swift).b; buf[tmp + 2] = C[prev_level[i-st_col] ].fs( curr_row >> swift, i >> swift).g; buf[tmp + 3] = C[prev_level[i-st_col] ].fs( curr_row >> swift, i >> swift).r; } else { buf [ tmp ] = compute_color ( &C[prev_level[i-st_col] ].fs( curr_row >> swift, i >> swift).r ); } } } } // for curr_row // reclaim memory delete tcurr[ HEADER.NOS_LEVEL]; //for (int i=0;i max_row) st_row_1 = max_row; if (en_row_1 > max_row) en_row_1 = max_row; int st_col_1 =(int) (st_col * level_1 + .5); int en_col_1 =(int) (en_col * level_1 + .5); item **curr = new (item *) [diff_level]; int *reuse = new int [diff_level+1]; int *look_up = new int [diff_col]; char *flag = new char[diff_col]; curr[diff_level - 1] = new item(0, HEADER.LOWEST_RESOLUTION_WIDTH/2-1, NULL); for (int i=level; i < HEADER.NOS_LEVEL; i ++) curr[i-level] = T[i][st_row_1>>(i-level+1)]. first_occurance(st_col_1>>(i-level+1), (en_col_1>>(i-level+1))+1); // // The array 'reuse' is tricky one. It determines the reusability // of the data in a row, and of the pointers in curr. // It's like this. // For a level 0 image, (highest resolution level,) only the // current row could use it. // And for a level 1 image, 2 rows in the original image // becomes 1 row, by taking the average. So basically, // Similarly, in a level n image, (2 ** n) rows in original // would packed into 1 row. (** is the Fortran notation // of power operation.) // For further information, try to understand some data structure in // sparse_2.c and sparse_mask.c. Also, try to understand some // idea on multi-resolution analysis. // for (int i = level; i < HEADER.NOS_LEVEL+2; i++) reuse[i-level] = (1 << (i-level)) - 1; // // The array 'flag' is storing the resolution level where // each column is using in the previous row. // Most of the time, the resolution level is the same // because the expansion of the lower resolution. // memset(flag, HEADER.NOS_LEVEL+1, diff_col); for (int i = st_col+1 ; i < en_col ; i ++) look_up[i-st_col] = (int) (i * level_1 + .5); look_up[0] = st_col_1; look_up[diff_col-1] = en_col_1; for (int i= st_row; i<= en_row; i++) { int i_1; int count = diff_col; unsigned char *buf_ptr = buf + (i - st_row) * scanline; unsigned char *data = buf_ptr - scanline; if (i >= st_col && i <= en_col) i_1 = look_up[i - st_col]; else i_1 = (int) (i * level_1 + .5); if (i_1 > max_row) i_1 = max_row; for (int j = level, j0 = 0; count != 0 && j <= HEADER.NOS_LEVEL; j++, j0++) { int cur_row = i_1 >> j0; int start = st_col_1 >> (j0+1); int stop = (en_col_1 >> (j0+1))+1; if (i != st_row) { if (j != HEADER.NOS_LEVEL) { for (int m = i_1; m > i_2; m --) { if ((reuse[j0+1] & m) == 0) { curr[j0] = T[j][m>>(1+j0)].first_occurance(start, stop); break; } } } for (int m = i_1; m > i_2; m --) { if ((reuse[j0] & m) == 0) { // if current row cannot reuse level 'j' resolution used in previous // row, modify the flag element. for (int k = 0 ; k < diff_col ; k ++) { if (flag[k] == j) flag[k] = HEADER.NOS_LEVEL+1; } break; } } } for (item *cur_item = curr[j0]; count > 0 && cur_item != NULL; cur_item = cur_item->next) { int st0 = ((cur_item->start_from) << 1); int en0 = ((cur_item->end_at+1) << 1); int st = (int) ((st0 << j0) / level_1 +.5); int en = (int) ((en0 << j0) / level_1 +.5); en0 --; int usng = -1, store, usng1; unsigned char store3[3]; if (st > en_col) break; if (st < st_col) st = st_col; if (en > en_col) en = en_col +1; for (int k = st, k_0 = st - st_col; k < en && count > 0; k++, k_0++) { // // If reuse flag is smaller that level 'j', than we have already // processed this column. // if (flag[k_0] < j) continue; // // If reuse flag is equal to level 'j', then reuse the previous // row's data. // if (flag[k_0] == j) { if (byte_per_pixel == 3) { bcopy(&data[k_0 * 4 + 1], store3, 3); bcopy(store3, &buf_ptr[k_0 *4 + 1], 3); } else { store = data[k_0]; buf_ptr [k_0] = store; } count --; continue; } // // Otherwise, set to reuse flag to this level and begin to // calculate this pixel. // flag[k_0] = j; if (usng != (usng1 = (look_up[k-st_col]>>j0))) { usng = usng1; if (usng > en0) usng1 = en0; else if (usng < st0) usng1 = st0; unsigned char *ptr = &C[j].fs(cur_row, usng1).r; if (byte_per_pixel == 3) { store3[0] = ptr[2]; store3[1] = ptr[1]; store3[2] = ptr[0]; } else { store = compute_color(ptr); } } if (byte_per_pixel == 3) bcopy(store3, &buf_ptr[k_0 *4 +1], 3); else buf_ptr [k_0] = store; count --; } } } i_2 = i_1; } delete [] look_up; delete [] flag; delete [] reuse; delete curr[diff_level-1]; delete [] curr; }