1219b2ee8SDavid du Colombier #include <u.h>
2219b2ee8SDavid du Colombier #include <libc.h>
3219b2ee8SDavid du Colombier #include <bio.h>
4219b2ee8SDavid du Colombier #include "sky.h"
5219b2ee8SDavid du Colombier
6219b2ee8SDavid du Colombier static void unshuffle(Pix*, int, int, Pix*);
7219b2ee8SDavid du Colombier static void unshuffle1(Pix*, int, Pix*);
8219b2ee8SDavid du Colombier
9219b2ee8SDavid du Colombier void
hinv(Pix * a,int nx,int ny)10219b2ee8SDavid du Colombier hinv(Pix *a, int nx, int ny)
11219b2ee8SDavid du Colombier {
12219b2ee8SDavid du Colombier int nmax, log2n, h0, hx, hy, hc, i, j, k;
13219b2ee8SDavid du Colombier int nxtop, nytop, nxf, nyf, c;
14219b2ee8SDavid du Colombier int oddx, oddy;
15219b2ee8SDavid du Colombier int shift;
16219b2ee8SDavid du Colombier int s10, s00;
17219b2ee8SDavid du Colombier Pix *tmp;
18219b2ee8SDavid du Colombier
19219b2ee8SDavid du Colombier /*
20219b2ee8SDavid du Colombier * log2n is log2 of max(nx, ny) rounded up to next power of 2
21219b2ee8SDavid du Colombier */
22219b2ee8SDavid du Colombier nmax = ny;
23219b2ee8SDavid du Colombier if(nx > nmax)
24219b2ee8SDavid du Colombier nmax = nx;
25219b2ee8SDavid du Colombier log2n = log(nmax)/LN2 + 0.5;
26219b2ee8SDavid du Colombier if(nmax > (1<<log2n))
27219b2ee8SDavid du Colombier log2n++;
28219b2ee8SDavid du Colombier
29219b2ee8SDavid du Colombier /*
30219b2ee8SDavid du Colombier * get temporary storage for shuffling elements
31219b2ee8SDavid du Colombier */
32219b2ee8SDavid du Colombier tmp = (Pix*)malloc(((nmax+1)/2) * sizeof(*tmp));
33*59cc4ca5SDavid du Colombier if(tmp == nil) {
34219b2ee8SDavid du Colombier fprint(2, "hinv: insufficient memory\n");
35219b2ee8SDavid du Colombier exits("memory");
36219b2ee8SDavid du Colombier }
37219b2ee8SDavid du Colombier
38219b2ee8SDavid du Colombier /*
39219b2ee8SDavid du Colombier * do log2n expansions
40219b2ee8SDavid du Colombier *
41219b2ee8SDavid du Colombier * We're indexing a as a 2-D array with dimensions (nx,ny).
42219b2ee8SDavid du Colombier */
43219b2ee8SDavid du Colombier shift = 1;
44219b2ee8SDavid du Colombier nxtop = 1;
45219b2ee8SDavid du Colombier nytop = 1;
46219b2ee8SDavid du Colombier nxf = nx;
47219b2ee8SDavid du Colombier nyf = ny;
48219b2ee8SDavid du Colombier c = 1<<log2n;
49219b2ee8SDavid du Colombier for(k = log2n-1; k>=0; k--) {
50219b2ee8SDavid du Colombier /*
51219b2ee8SDavid du Colombier * this somewhat cryptic code generates the sequence
52219b2ee8SDavid du Colombier * ntop[k-1] = (ntop[k]+1)/2, where ntop[log2n] = n
53219b2ee8SDavid du Colombier */
54219b2ee8SDavid du Colombier c = c>>1;
55219b2ee8SDavid du Colombier nxtop = nxtop<<1;
56219b2ee8SDavid du Colombier nytop = nytop<<1;
57219b2ee8SDavid du Colombier if(nxf <= c)
58219b2ee8SDavid du Colombier nxtop--;
59219b2ee8SDavid du Colombier else
60219b2ee8SDavid du Colombier nxf -= c;
61219b2ee8SDavid du Colombier if(nyf <= c)
62219b2ee8SDavid du Colombier nytop--;
63219b2ee8SDavid du Colombier else
64219b2ee8SDavid du Colombier nyf -= c;
65219b2ee8SDavid du Colombier
66219b2ee8SDavid du Colombier /*
67219b2ee8SDavid du Colombier * halve divisors on last pass
68219b2ee8SDavid du Colombier */
69219b2ee8SDavid du Colombier if(k == 0)
70219b2ee8SDavid du Colombier shift = 0;
71219b2ee8SDavid du Colombier
72219b2ee8SDavid du Colombier /*
73219b2ee8SDavid du Colombier * unshuffle in each dimension to interleave coefficients
74219b2ee8SDavid du Colombier */
75219b2ee8SDavid du Colombier for(i = 0; i<nxtop; i++)
76219b2ee8SDavid du Colombier unshuffle1(&a[ny*i], nytop, tmp);
77219b2ee8SDavid du Colombier for(j = 0; j<nytop; j++)
78219b2ee8SDavid du Colombier unshuffle(&a[j], nxtop, ny, tmp);
79219b2ee8SDavid du Colombier oddx = nxtop & 1;
80219b2ee8SDavid du Colombier oddy = nytop & 1;
81219b2ee8SDavid du Colombier for(i = 0; i<nxtop-oddx; i += 2) {
82219b2ee8SDavid du Colombier s00 = ny*i; /* s00 is index of a[i,j] */
83219b2ee8SDavid du Colombier s10 = s00+ny; /* s10 is index of a[i+1,j] */
84219b2ee8SDavid du Colombier for(j = 0; j<nytop-oddy; j += 2) {
85219b2ee8SDavid du Colombier /*
86219b2ee8SDavid du Colombier * Multiply h0,hx,hy,hc by 2 (1 the last time through).
87219b2ee8SDavid du Colombier */
88219b2ee8SDavid du Colombier h0 = a[s00 ] << shift;
89219b2ee8SDavid du Colombier hx = a[s10 ] << shift;
90219b2ee8SDavid du Colombier hy = a[s00+1] << shift;
91219b2ee8SDavid du Colombier hc = a[s10+1] << shift;
92219b2ee8SDavid du Colombier
93219b2ee8SDavid du Colombier /*
94219b2ee8SDavid du Colombier * Divide sums by 4 (shift right 2 bits).
95219b2ee8SDavid du Colombier * Add 1 to round -- note that these values are always
96219b2ee8SDavid du Colombier * positive so we don't need to do anything special
97219b2ee8SDavid du Colombier * for rounding negative numbers.
98219b2ee8SDavid du Colombier */
99219b2ee8SDavid du Colombier a[s10+1] = (h0 + hx + hy + hc + 2) >> 2;
100219b2ee8SDavid du Colombier a[s10 ] = (h0 + hx - hy - hc + 2) >> 2;
101219b2ee8SDavid du Colombier a[s00+1] = (h0 - hx + hy - hc + 2) >> 2;
102219b2ee8SDavid du Colombier a[s00 ] = (h0 - hx - hy + hc + 2) >> 2;
103219b2ee8SDavid du Colombier s00 += 2;
104219b2ee8SDavid du Colombier s10 += 2;
105219b2ee8SDavid du Colombier }
106219b2ee8SDavid du Colombier if(oddy) {
107219b2ee8SDavid du Colombier /*
108219b2ee8SDavid du Colombier * do last element in row if row length is odd
109219b2ee8SDavid du Colombier * s00+1, s10+1 are off edge
110219b2ee8SDavid du Colombier */
111219b2ee8SDavid du Colombier h0 = a[s00 ] << shift;
112219b2ee8SDavid du Colombier hx = a[s10 ] << shift;
113219b2ee8SDavid du Colombier a[s10 ] = (h0 + hx + 2) >> 2;
114219b2ee8SDavid du Colombier a[s00 ] = (h0 - hx + 2) >> 2;
115219b2ee8SDavid du Colombier }
116219b2ee8SDavid du Colombier }
117219b2ee8SDavid du Colombier if(oddx) {
118219b2ee8SDavid du Colombier /*
119219b2ee8SDavid du Colombier * do last row if column length is odd
120219b2ee8SDavid du Colombier * s10, s10+1 are off edge
121219b2ee8SDavid du Colombier */
122219b2ee8SDavid du Colombier s00 = ny*i;
123219b2ee8SDavid du Colombier for(j = 0; j<nytop-oddy; j += 2) {
124219b2ee8SDavid du Colombier h0 = a[s00 ] << shift;
125219b2ee8SDavid du Colombier hy = a[s00+1] << shift;
126219b2ee8SDavid du Colombier a[s00+1] = (h0 + hy + 2) >> 2;
127219b2ee8SDavid du Colombier a[s00 ] = (h0 - hy + 2) >> 2;
128219b2ee8SDavid du Colombier s00 += 2;
129219b2ee8SDavid du Colombier }
130219b2ee8SDavid du Colombier if(oddy) {
131219b2ee8SDavid du Colombier /*
132219b2ee8SDavid du Colombier * do corner element if both row and column lengths are odd
133219b2ee8SDavid du Colombier * s00+1, s10, s10+1 are off edge
134219b2ee8SDavid du Colombier */
135219b2ee8SDavid du Colombier h0 = a[s00 ] << shift;
136219b2ee8SDavid du Colombier a[s00 ] = (h0 + 2) >> 2;
137219b2ee8SDavid du Colombier }
138219b2ee8SDavid du Colombier }
139219b2ee8SDavid du Colombier }
140219b2ee8SDavid du Colombier free(tmp);
141219b2ee8SDavid du Colombier }
142219b2ee8SDavid du Colombier
143219b2ee8SDavid du Colombier static
144219b2ee8SDavid du Colombier void
unshuffle(Pix * a,int n,int n2,Pix * tmp)145219b2ee8SDavid du Colombier unshuffle(Pix *a, int n, int n2, Pix *tmp)
146219b2ee8SDavid du Colombier {
147219b2ee8SDavid du Colombier int i;
148219b2ee8SDavid du Colombier int nhalf, twon2, n2xnhalf;
149219b2ee8SDavid du Colombier Pix *p1, *p2, *pt;
150219b2ee8SDavid du Colombier
151219b2ee8SDavid du Colombier twon2 = n2<<1;
152219b2ee8SDavid du Colombier nhalf = (n+1)>>1;
153219b2ee8SDavid du Colombier n2xnhalf = n2*nhalf; /* pointer to a[i] */
154219b2ee8SDavid du Colombier
155219b2ee8SDavid du Colombier /*
156219b2ee8SDavid du Colombier * copy 2nd half of array to tmp
157219b2ee8SDavid du Colombier */
158219b2ee8SDavid du Colombier pt = tmp;
159219b2ee8SDavid du Colombier p1 = &a[n2xnhalf]; /* pointer to a[i] */
160219b2ee8SDavid du Colombier for(i=nhalf; i<n; i++) {
161219b2ee8SDavid du Colombier *pt = *p1;
162219b2ee8SDavid du Colombier pt++;
163219b2ee8SDavid du Colombier p1 += n2;
164219b2ee8SDavid du Colombier }
165219b2ee8SDavid du Colombier
166219b2ee8SDavid du Colombier /*
167219b2ee8SDavid du Colombier * distribute 1st half of array to even elements
168219b2ee8SDavid du Colombier */
169219b2ee8SDavid du Colombier p2 = &a[n2xnhalf]; /* pointer to a[i] */
170219b2ee8SDavid du Colombier p1 = &a[n2xnhalf<<1]; /* pointer to a[2*i] */
171219b2ee8SDavid du Colombier for(i=nhalf-1; i>=0; i--) {
172219b2ee8SDavid du Colombier p1 -= twon2;
173219b2ee8SDavid du Colombier p2 -= n2;
174219b2ee8SDavid du Colombier *p1 = *p2;
175219b2ee8SDavid du Colombier }
176219b2ee8SDavid du Colombier
177219b2ee8SDavid du Colombier /*
178219b2ee8SDavid du Colombier * now distribute 2nd half of array (in tmp) to odd elements
179219b2ee8SDavid du Colombier */
180219b2ee8SDavid du Colombier pt = tmp;
181219b2ee8SDavid du Colombier p1 = &a[n2]; /* pointer to a[i] */
182219b2ee8SDavid du Colombier for(i=1; i<n; i+=2) {
183219b2ee8SDavid du Colombier *p1 = *pt;
184219b2ee8SDavid du Colombier p1 += twon2;
185219b2ee8SDavid du Colombier pt++;
186219b2ee8SDavid du Colombier }
187219b2ee8SDavid du Colombier }
188219b2ee8SDavid du Colombier
189219b2ee8SDavid du Colombier static
190219b2ee8SDavid du Colombier void
unshuffle1(Pix * a,int n,Pix * tmp)191219b2ee8SDavid du Colombier unshuffle1(Pix *a, int n, Pix *tmp)
192219b2ee8SDavid du Colombier {
193219b2ee8SDavid du Colombier int i;
194219b2ee8SDavid du Colombier int nhalf;
195219b2ee8SDavid du Colombier Pix *p1, *p2, *pt;
196219b2ee8SDavid du Colombier
197219b2ee8SDavid du Colombier nhalf = (n+1) >> 1;
198219b2ee8SDavid du Colombier
199219b2ee8SDavid du Colombier /*
200219b2ee8SDavid du Colombier * copy 2nd half of array to tmp
201219b2ee8SDavid du Colombier */
202219b2ee8SDavid du Colombier pt = tmp;
203219b2ee8SDavid du Colombier p1 = &a[nhalf]; /* pointer to a[i] */
204219b2ee8SDavid du Colombier for(i=nhalf; i<n; i++) {
205219b2ee8SDavid du Colombier *pt = *p1;
206219b2ee8SDavid du Colombier pt++;
207219b2ee8SDavid du Colombier p1++;
208219b2ee8SDavid du Colombier }
209219b2ee8SDavid du Colombier
210219b2ee8SDavid du Colombier /*
211219b2ee8SDavid du Colombier * distribute 1st half of array to even elements
212219b2ee8SDavid du Colombier */
213219b2ee8SDavid du Colombier p2 = &a[nhalf]; /* pointer to a[i] */
214219b2ee8SDavid du Colombier p1 = &a[nhalf<<1]; /* pointer to a[2*i] */
215219b2ee8SDavid du Colombier for(i=nhalf-1; i>=0; i--) {
216219b2ee8SDavid du Colombier p1 -= 2;
217219b2ee8SDavid du Colombier p2--;
218219b2ee8SDavid du Colombier *p1 = *p2;
219219b2ee8SDavid du Colombier }
220219b2ee8SDavid du Colombier
221219b2ee8SDavid du Colombier /*
222219b2ee8SDavid du Colombier * now distribute 2nd half of array (in tmp) to odd elements
223219b2ee8SDavid du Colombier */
224219b2ee8SDavid du Colombier pt = tmp;
225219b2ee8SDavid du Colombier p1 = &a[1]; /* pointer to a[i] */
226219b2ee8SDavid du Colombier for(i=1; i<n; i+=2) {
227219b2ee8SDavid du Colombier *p1 = *pt;
228219b2ee8SDavid du Colombier p1 += 2;
229219b2ee8SDavid du Colombier pt++;
230219b2ee8SDavid du Colombier }
231219b2ee8SDavid du Colombier }
232