| #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++; |
| } |
| } |