ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcode_norm.c
Revision: 2.12
Committed: Sat Jun 7 05:09:46 2025 UTC (2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.11: +1 -2 lines
Log Message:
refactor: Put some declarations into "paths.h" and included in "platform.h"

File Contents

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