xref: /plan9/sys/src/cmd/scat/hinv.c (revision 59cc4ca53493a3c6d2349fe2b7f7c40f7dce7294)
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