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 (13 days, 21 hours 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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rcode_norm.c,v 2.11 2025/06/04 22:34:27 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
17 /* Report usage error and exit */
18 static void
19 usage_exit(int code)
20 {
21 fputs("Usage: ", stderr);
22 fputs(progname, stderr);
23 fputs(" [-h[io]][-H[io]][-f[afd]][-x xr -y yr] [input [output.nrm]]\n", stderr);
24 fputs(" Or: ", stderr);
25 fputs(progname, stderr);
26 fputs(" -r [-i][-u][-h[io]][-H[io]][-f[afd]] [input.nrm [output]]\n",
27 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 if (!strcmp(ncp->inpfmt, "ascii"))
40 ncp->format = 'a';
41 else if (!strcmp(ncp->inpfmt, "float"))
42 ncp->format = 'f';
43 else if (!strcmp(ncp->inpfmt, "double"))
44 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 if (ncp->format == 'a')
54 SET_FILE_TEXT(ncp->finp);
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 if (ncp->swapped)
69 swap32((char *)nrm, 3);
70 break;
71 case 'd': {
72 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 #else
80 case 'f': {
81 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 case 'd':
89 ok = (getbinary(nrm, sizeof(*nrm), 3, ncp->finp) == 3);
90 if (ncp->swapped)
91 swap64((char *)nrm, 3);
92 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
193 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 int xres=0, yres=0;
221 int reverse = 0;
222 int bypixel = 0;
223 int unbuffered = 0;
224 NORMCODEC nc;
225 int a;
226 /* set global progname */
227 fixargv0(argv[0]);
228 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 case 'x':
283 xres = atoi(argv[++a]);
284 break;
285 case 'y':
286 yres = atoi(argv[++a]);
287 break;
288 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 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 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 nc.hdrflags &= ~HF_RESOUT;
327 }
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 SET_FILE_BINARY(nc.finp); /* starting assumption */
344 SET_FILE_BINARY(stdout);
345 #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
353 if (reverse && nc.format == 'a')
354 SET_FILE_TEXT(stdout);
355 /* 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 }