ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/rcode_norm.c
Revision: 2.11
Committed: Wed Jun 4 22:34:27 2025 UTC (45 hours, 26 minutes ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.10: +2 -1 lines
Log Message:
fix: Fixed reference to fixargv0()

File Contents

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