ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcode_norm.c
Revision: 2.1
Committed: Fri Jul 19 02:18:44 2019 UTC (4 years, 8 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Created rcode_norm tool for encoding & decoding 32-bit surface normal maps

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2     static const char RCSid[] = "$Id: rcode_depth.c,v 2.2 2019/07/18 19:13:44 greg Exp $";
3     #endif
4     /*
5     * Encode and decode surface normal map using 32-bit integers
6     */
7    
8     #include "copyright.h"
9    
10     #include <stdlib.h>
11     #include "platform.h"
12     #include "rtio.h"
13     #include "rtmath.h"
14     #include "normcodec.h"
15    
16     char *progname; /* set in main() */
17    
18    
19     /* Report usage error and exit */
20     static void
21     usage_exit(int code)
22     {
23     fputs("Usage: ", stderr);
24     fputs(progname, stderr);
25     fputs(" [-h[io]][-H[io]][-f[afd]] [input [output]]\n", stderr);
26     fputs(" Or: ", stderr);
27     fputs(progname, stderr);
28     fputs(" -r [-i][-u][-h[io]][-H[io]][-f[afd]] [input [output]]\n",
29     stderr);
30     exit(code);
31     }
32    
33    
34     /* Encode normals from input stream */
35     static int
36     encode_normals(NORMCODEC *ncp)
37     {
38     long nexpected = (long)ncp->res.xr * ncp->res.yr;
39    
40     if (ncp->inpfmt[0]) {
41     if (strcasestr(ncp->inpfmt, "ascii") != NULL)
42     ncp->format = 'a';
43     else if (strcasestr(ncp->inpfmt, "float") != NULL)
44     ncp->format = 'f';
45     else if (strcasestr(ncp->inpfmt, "double") != NULL)
46     ncp->format = 'd';
47     else {
48     fputs(ncp->inpname, stderr);
49     fputs(": unsupported input format: ", stderr);
50     fputs(ncp->inpfmt, stderr);
51     fputc('\n', stderr);
52     return 0;
53     }
54     }
55    
56     do {
57     int ok = 0;
58     FVECT nrm;
59    
60     switch (ncp->format) {
61     case 'a':
62     ok = (fscanf(ncp->finp, FVFORMAT,
63     &nrm[0], &nrm[1], &nrm[2]) == 3);
64     break;
65     #ifdef SMLFLT
66     case 'f':
67     ok = (getbinary(nrm, sizeof(*nrm), 3, ncp->finp) == 3);
68     break;
69     case 'd': {
70     double nrmd[3];
71     ok = (getbinary(nrmd, sizeof(*nrmd),
72     3, ncp->finp) == 3);
73     if (ok) VCOPY(nrm, nrmd);
74     }
75     break;
76     #else
77     case 'f': {
78     float nrmf[3];
79     ok = (getbinary(nrmf, sizeof(*nrmf),
80     3, ncp->finp) == 3);
81     if (ok) VCOPY(nrm, nrmf);
82     }
83     break;
84     case 'd':
85     ok = (getbinary(nrm, sizeof(*nrm), 3, ncp->finp) == 3);
86     break;
87     #endif
88     }
89     if (!ok)
90     break;
91    
92     normalize(nrm);
93     putint(encodedir(nrm), 4, stdout);
94    
95     } while (--nexpected);
96    
97     if (nexpected > 0) {
98     fputs(ncp->inpname, stderr);
99     fputs(": fewer normals than expected\n", stderr);
100     return 0;
101     }
102     return 1;
103     }
104    
105    
106     /* Output the given normal to stdout */
107     static void
108     output_normal(NORMCODEC *ncp, FVECT nrm)
109     {
110     switch (ncp->format) {
111     case 'a':
112     printf("%.9f %.9f %.9f\n", nrm[0], nrm[1], nrm[2]);
113     break;
114     #ifdef SMLFLT
115     case 'f':
116     putbinary(nrm, sizeof(*nrm), 3, stdout);
117     break;
118     case 'd': {
119     double nrmd[3];
120     VCOPY(nrmd, nrm);
121     putbinary(nrmd, sizeof(*nrmd), 3, stdout);
122     }
123     break;
124     #else
125     case 'f': {
126     float nrmf[3];
127     VCOPY(nrmf, nrm);
128     putbinary(nrmf, sizeof(*nrmf), 3, stdout);
129     }
130     break;
131     case 'd':
132     putbinary(nrm, sizeof(*nrm), 3, stdout);
133     break;
134     #endif
135     }
136     }
137    
138    
139     /* Decode normals from input stream */
140     static int
141     decode_normals(NORMCODEC *ncp)
142     {
143     long nexpected = (long)ncp->res.xr * ncp->res.yr;
144    
145     if (!check_decode_normals(ncp))
146     return 0;
147    
148     do {
149     FVECT nrm;
150    
151     if (decode_normal_next(nrm, ncp) < 0)
152     break;
153    
154     output_normal(ncp, nrm);
155    
156     } while (--nexpected);
157    
158     if (nexpected > 0) {
159     fputs(ncp->inpname, stderr);
160     fputs(": unexpected EOF\n", stderr);
161     return 0;
162     }
163     return 1;
164     }
165    
166    
167     /* Decode normals at particular pixels given on standard input */
168     static int
169     pixel_normals(NORMCODEC *ncp, int unbuf)
170     {
171     int x, y;
172     FVECT nrm;
173    
174     if (ncp->finp == stdin) {
175     fputs(progname, stderr);
176     fputs(": <stdin> used for encoded normals\n", stderr);
177     return 0;
178     }
179     if (!check_decode_normals(ncp))
180     return 0;
181     if (ncp->res.rt != PIXSTANDARD) {
182     fputs(progname, stderr);
183     fputs(": can only handle standard pixel ordering\n", stderr);
184     return 0;
185     }
186     while (scanf("%d %d", &x, &y) == 2) {
187    
188     y = ncp->res.yr-1 - y;
189    
190     if (decode_normal_pix(nrm, ncp, x, y) < 0)
191     return 0;
192    
193     output_normal(ncp, nrm);
194    
195     if (unbuf && fflush(stdout) == EOF) {
196     fputs(progname, stderr);
197     fputs(": write error on output\n", stderr);
198     return 0;
199     }
200     }
201     if (!feof(stdin)) {
202     fputs(progname, stderr);
203     fputs(": non-integer as pixel index\n", stderr);
204     return 0;
205     }
206     return 1;
207     }
208    
209    
210     int
211     main(int argc, char *argv[])
212     {
213     int reverse = 0;
214     int bypixel = 0;
215     int unbuffered = 0;
216     NORMCODEC nc;
217     int a;
218    
219     progname = argv[0];
220     set_nc_defaults(&nc);
221     nc.hdrflags = HF_ALL;
222     for (a = 1; a < argc && argv[a][0] == '-'; a++)
223     switch (argv[a][1]) {
224     case 'r':
225     reverse++;
226     break;
227     case 'f':
228     switch (argv[a][2]) {
229     case 'f':
230     case 'd':
231     case 'a':
232     nc.format = argv[a][2];
233     break;
234     default:
235     fputs(progname, stderr);
236     fputs(": unsupported -f? format\n", stderr);
237     usage_exit(1);
238     }
239     break;
240     case 'h':
241     switch (argv[a][2]) {
242     case '\0':
243     nc.hdrflags &= ~(HF_HEADIN|HF_HEADOUT);
244     break;
245     case 'i':
246     case 'I':
247     nc.hdrflags &= ~HF_HEADIN;
248     break;
249     case 'o':
250     case 'O':
251     nc.hdrflags &= ~HF_HEADOUT;
252     break;
253     default:
254     usage_exit(1);
255     }
256     break;
257     case 'H':
258     switch (argv[a][2]) {
259     case '\0':
260     nc.hdrflags &= ~(HF_RESIN|HF_RESOUT);
261     break;
262     case 'i':
263     case 'I':
264     nc.hdrflags &= ~HF_RESIN;
265     break;
266     case 'o':
267     case 'O':
268     nc.hdrflags &= ~HF_RESOUT;
269     break;
270     default:
271     usage_exit(1);
272     }
273     break;
274     case 'i':
275     bypixel++;
276     break;
277     case 'u':
278     unbuffered++;
279     break;
280     default:
281     usage_exit(1);
282     }
283     nc.hdrflags |= !reverse * HF_ENCODE;
284    
285     if ((nc.hdrflags & (HF_RESIN|HF_RESOUT)) == HF_RESOUT) {
286     fputs(progname, stderr);
287     fputs(": unknown resolution for output\n", stderr);
288     return 1;
289     }
290     if (bypixel) {
291     if (!reverse) {
292     fputs(progname, stderr);
293     fputs(": -i only supported with -r option\n",
294     stderr);
295     usage_exit(1);
296     }
297     if (a >= argc) {
298     fputs(progname, stderr);
299     fputs(": -i option requires input file\n", stderr);
300     usage_exit(1);
301     }
302     if (!(nc.hdrflags & HF_RESIN)) {
303     fputs(progname, stderr);
304     fputs(": -i option requires input resolution\n", stderr);
305     usage_exit(1);
306     }
307     nc.hdrflags &= ~(HF_HEADOUT|HF_RESOUT);
308     }
309     if (a < argc-2) {
310     fputs(progname, stderr);
311     fputs(": too many file arguments\n", stderr);
312     usage_exit(1);
313     }
314     if (a < argc && !(nc.finp = fopen(nc.inpname=argv[a], "r"))) {
315     fputs(nc.inpname, stderr);
316     fputs(": cannot open for reading\n", stderr);
317     return 1;
318     }
319     if (a+1 < argc && !freopen(argv[a+1], "w", stdout)) {
320     fputs(argv[a+1], stderr);
321     fputs(": cannot open for writing\n", stderr);
322     return 1;
323     }
324     SET_FILE_BINARY(nc.finp);
325     if (reverse || nc.format != 'a')
326     SET_FILE_BINARY(stdout);
327     #ifdef getc_unlocked /* avoid stupid semaphores */
328     flockfile(nc.finp);
329     flockfile(stdout);
330     #endif
331     /* read/copy header */
332     if (!process_nc_header(&nc, a, argv))
333     return 1;
334     /* process data */
335     if (!reverse) {
336     if (!encode_normals(&nc))
337     return 1;
338     } else if (bypixel) {
339     if (!pixel_normals(&nc, unbuffered))
340     return 1;
341     } else if (!decode_normals(&nc))
342     return 1;
343    
344     if (fflush(stdout) == EOF) {
345     fputs(progname, stderr);
346     fputs(": error writing output\n", stderr);
347     return 1;
348     }
349     return 0;
350     }