|  | #include	<u.h> | 
|  | #include	<libc.h> | 
|  | #include	<bio.h> | 
|  | #include	"sky.h" | 
|  |  | 
|  | static	void	unshuffle(Pix*, int, int, Pix*); | 
|  | static	void	unshuffle1(Pix*, int, Pix*); | 
|  |  | 
|  | void | 
|  | hinv(Pix *a, int nx, int ny) | 
|  | { | 
|  | int nmax, log2n, h0, hx, hy, hc, i, j, k; | 
|  | int nxtop, nytop, nxf, nyf, c; | 
|  | int oddx, oddy; | 
|  | int shift; | 
|  | int s10, s00; | 
|  | Pix *tmp; | 
|  |  | 
|  | /* | 
|  | * log2n is log2 of max(nx, ny) rounded up to next power of 2 | 
|  | */ | 
|  | nmax = ny; | 
|  | if(nx > nmax) | 
|  | nmax = nx; | 
|  | log2n = log(nmax)/LN2 + 0.5; | 
|  | if(nmax > (1<<log2n)) | 
|  | log2n++; | 
|  |  | 
|  | /* | 
|  | * get temporary storage for shuffling elements | 
|  | */ | 
|  | tmp = (Pix*)malloc(((nmax+1)/2) * sizeof(*tmp)); | 
|  | if(tmp == nil) { | 
|  | fprint(2, "hinv: insufficient memory\n"); | 
|  | exits("memory"); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * do log2n expansions | 
|  | * | 
|  | * We're indexing a as a 2-D array with dimensions (nx,ny). | 
|  | */ | 
|  | shift = 1; | 
|  | nxtop = 1; | 
|  | nytop = 1; | 
|  | nxf = nx; | 
|  | nyf = ny; | 
|  | c = 1<<log2n; | 
|  | for(k = log2n-1; k>=0; k--) { | 
|  | /* | 
|  | * this somewhat cryptic code generates the sequence | 
|  | * ntop[k-1] = (ntop[k]+1)/2, where ntop[log2n] = n | 
|  | */ | 
|  | c = c>>1; | 
|  | nxtop = nxtop<<1; | 
|  | nytop = nytop<<1; | 
|  | if(nxf <= c) | 
|  | nxtop--; | 
|  | else | 
|  | nxf -= c; | 
|  | if(nyf <= c) | 
|  | nytop--; | 
|  | else | 
|  | nyf -= c; | 
|  |  | 
|  | /* | 
|  | * halve divisors on last pass | 
|  | */ | 
|  | if(k == 0) | 
|  | shift = 0; | 
|  |  | 
|  | /* | 
|  | * unshuffle in each dimension to interleave coefficients | 
|  | */ | 
|  | for(i = 0; i<nxtop; i++) | 
|  | unshuffle1(&a[ny*i], nytop, tmp); | 
|  | for(j = 0; j<nytop; j++) | 
|  | unshuffle(&a[j], nxtop, ny, tmp); | 
|  | oddx = nxtop & 1; | 
|  | oddy = nytop & 1; | 
|  | for(i = 0; i<nxtop-oddx; i += 2) { | 
|  | s00 = ny*i;			/* s00 is index of a[i,j]	*/ | 
|  | s10 = s00+ny;			/* s10 is index of a[i+1,j]	*/ | 
|  | for(j = 0; j<nytop-oddy; j += 2) { | 
|  | /* | 
|  | * Multiply h0,hx,hy,hc by 2 (1 the last time through). | 
|  | */ | 
|  | h0 = a[s00  ] << shift; | 
|  | hx = a[s10  ] << shift; | 
|  | hy = a[s00+1] << shift; | 
|  | hc = a[s10+1] << shift; | 
|  |  | 
|  | /* | 
|  | * Divide sums by 4 (shift right 2 bits). | 
|  | * Add 1 to round -- note that these values are always | 
|  | * positive so we don't need to do anything special | 
|  | * for rounding negative numbers. | 
|  | */ | 
|  | a[s10+1] = (h0 + hx + hy + hc + 2) >> 2; | 
|  | a[s10  ] = (h0 + hx - hy - hc + 2) >> 2; | 
|  | a[s00+1] = (h0 - hx + hy - hc + 2) >> 2; | 
|  | a[s00  ] = (h0 - hx - hy + hc + 2) >> 2; | 
|  | s00 += 2; | 
|  | s10 += 2; | 
|  | } | 
|  | if(oddy) { | 
|  | /* | 
|  | * do last element in row if row length is odd | 
|  | * s00+1, s10+1 are off edge | 
|  | */ | 
|  | h0 = a[s00  ] << shift; | 
|  | hx = a[s10  ] << shift; | 
|  | a[s10  ] = (h0 + hx + 2) >> 2; | 
|  | a[s00  ] = (h0 - hx + 2) >> 2; | 
|  | } | 
|  | } | 
|  | if(oddx) { | 
|  | /* | 
|  | * do last row if column length is odd | 
|  | * s10, s10+1 are off edge | 
|  | */ | 
|  | s00 = ny*i; | 
|  | for(j = 0; j<nytop-oddy; j += 2) { | 
|  | h0 = a[s00  ] << shift; | 
|  | hy = a[s00+1] << shift; | 
|  | a[s00+1] = (h0 + hy + 2) >> 2; | 
|  | a[s00  ] = (h0 - hy + 2) >> 2; | 
|  | s00 += 2; | 
|  | } | 
|  | if(oddy) { | 
|  | /* | 
|  | * do corner element if both row and column lengths are odd | 
|  | * s00+1, s10, s10+1 are off edge | 
|  | */ | 
|  | h0 = a[s00  ] << shift; | 
|  | a[s00  ] = (h0 + 2) >> 2; | 
|  | } | 
|  | } | 
|  | } | 
|  | free(tmp); | 
|  | } | 
|  |  | 
|  | static | 
|  | void | 
|  | unshuffle(Pix *a, int n, int n2, Pix *tmp) | 
|  | { | 
|  | int i; | 
|  | int nhalf, twon2, n2xnhalf; | 
|  | Pix *p1, *p2, *pt; | 
|  |  | 
|  | twon2 = n2<<1; | 
|  | nhalf = (n+1)>>1; | 
|  | n2xnhalf = n2*nhalf;		/* pointer to a[i] */ | 
|  |  | 
|  | /* | 
|  | * copy 2nd half of array to tmp | 
|  | */ | 
|  | pt = tmp; | 
|  | p1 = &a[n2xnhalf];		/* pointer to a[i] */ | 
|  | for(i=nhalf; i<n; i++) { | 
|  | *pt = *p1; | 
|  | pt++; | 
|  | p1 += n2; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * distribute 1st half of array to even elements | 
|  | */ | 
|  | p2 = &a[n2xnhalf];		/* pointer to a[i] */ | 
|  | p1 = &a[n2xnhalf<<1];		/* pointer to a[2*i] */ | 
|  | for(i=nhalf-1; i>=0; i--) { | 
|  | p1 -= twon2; | 
|  | p2 -= n2; | 
|  | *p1 = *p2; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * now distribute 2nd half of array (in tmp) to odd elements | 
|  | */ | 
|  | pt = tmp; | 
|  | p1 = &a[n2];			/* pointer to a[i] */ | 
|  | for(i=1; i<n; i+=2) { | 
|  | *p1 = *pt; | 
|  | p1 += twon2; | 
|  | pt++; | 
|  | } | 
|  | } | 
|  |  | 
|  | static | 
|  | void | 
|  | unshuffle1(Pix *a, int n, Pix *tmp) | 
|  | { | 
|  | int i; | 
|  | int nhalf; | 
|  | Pix *p1, *p2, *pt; | 
|  |  | 
|  | nhalf = (n+1) >> 1; | 
|  |  | 
|  | /* | 
|  | * copy 2nd half of array to tmp | 
|  | */ | 
|  | pt = tmp; | 
|  | p1 = &a[nhalf];				/* pointer to a[i]			*/ | 
|  | for(i=nhalf; i<n; i++) { | 
|  | *pt = *p1; | 
|  | pt++; | 
|  | p1++; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * distribute 1st half of array to even elements | 
|  | */ | 
|  | p2 = &a[nhalf];		/* pointer to a[i]			*/ | 
|  | p1 = &a[nhalf<<1];		/* pointer to a[2*i]		*/ | 
|  | for(i=nhalf-1; i>=0; i--) { | 
|  | p1 -= 2; | 
|  | p2--; | 
|  | *p1 = *p2; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * now distribute 2nd half of array (in tmp) to odd elements | 
|  | */ | 
|  | pt = tmp; | 
|  | p1 = &a[1];					/* pointer to a[i]			*/ | 
|  | for(i=1; i<n; i+=2) { | 
|  | *p1 = *pt; | 
|  | p1 += 2; | 
|  | pt++; | 
|  | } | 
|  | } |