ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/srcskipload.c
Revision: 2.3
Committed: Sat Jan 18 03:49:00 2025 UTC (3 months, 1 week ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.2: +1 -1 lines
State: FILE REMOVED
Log Message:
refactor: Removed experimental SRCSKIPOPT code

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: srcskipload.c,v 2.2 2024/12/13 00:48:19 greg Exp $";
3 #endif
4 /*
5 * Load source exclusion maps (BMP and MTX)
6 *
7 * External symbols declared in source.h
8 */
9
10 #ifdef SSKIPOPT /* currently an optional compile */
11
12 #include "copyright.h"
13
14 #include "platform.h"
15 #include "paths.h"
16 #include "ray.h"
17 #include "source.h"
18 #include "bmpfile.h"
19 #include "resolu.h"
20
21 int sskip_dim[2] = {0,0}; /* source skip image size */
22
23 /* correction file types */
24 enum {CFnone=0, CFfloatY, CFbmpY8};
25
26 /* struct for bitmap file loading */
27 typedef struct skipbmp {
28 struct skipbmp *next; /* next in skip list */
29 BMPReader *bmp; /* BMP file reader */
30 uby8 *sfl; /* corresponding sources */
31 char bname[1]; /* BMP file name */
32 } SKIPBMP;
33
34 /* holder for source exclusion images */
35 struct {
36 SKIPBMP *sbmplist; /* list of BMP inputs */
37 int cftype; /* correction file type */
38 union {
39 struct {
40 int fd;
41 int dstart;
42 } Y; /* float Y input */
43 BMPReader *bmp; /* BMP input pointer */
44 } cf; /* correction file input */
45 int *ndxmap; /* allocated index map */
46 float *corrmap; /* allocated correction map */
47 char cfname[MAXSTR]; /* correction file name */
48 } skipin; /* just need the one */
49
50 /* call-back for matrix header line */
51 static int
52 check_mtx(char *hl, void *p)
53 {
54 int *dim = (int *)p;
55 char fmt[MAXFMTLEN];
56 int rv;
57
58 if ((rv = isbigendian(hl)) >= 0) {
59 if (rv != nativebigendian()) {
60 eputs("cannot handle byte-swapped data\n");
61 return(-1);
62 }
63 return(1);
64 }
65 if (!strncmp(hl, "NCOLS=", 6)) {
66 dim[0] = atoi(hl+6);
67 if (dim[0] <= 0)
68 return(-1);
69 return(1);
70 }
71 if (!strncmp(hl, "NROWS=", 6)) {
72 dim[1] = atoi(hl+6);
73 if (dim[1] <= 0)
74 return(-1);
75 return(1);
76 }
77 if (isncomp(hl)) {
78 if (ncompval(hl) != 1) {
79 eputs("require single component\n");
80 return(-1);
81 }
82 return(1);
83 }
84 if (formatval(fmt, hl)) {
85 if (strcmp(fmt, "float")) {
86 eputs("require binary float format\n");
87 return(-1);
88 }
89 return(1);
90 }
91 return(0);
92 }
93
94 /* private call to open floating-point matrix and check dimensions */
95 static void
96 open_float_mtx()
97 {
98 int mydim[2];
99 FILE *fp;
100
101 skipin.cf.Y.fd = open(skipin.cfname, O_RDONLY);
102 if (skipin.cf.Y.fd < 0) {
103 sprintf(errmsg, "cannot open matrix '%s'", skipin.cfname);
104 error(SYSTEM, errmsg);
105 }
106 SET_FD_BINARY(skipin.cf.Y.fd); /* get temporary FILE pointer */
107 fp = fdopen(dup(skipin.cf.Y.fd), "rb");
108 if (fp == NULL)
109 error(SYSTEM, "out of memory in open_float_mtx()");
110 mydim[0] = mydim[1] = 0; /* check header format, etc. */
111 if (getheader(fp, check_mtx, mydim) < 0)
112 goto badheader;
113 if (!mydim[0] | !mydim[1] &&
114 !fscnresolu(&mydim[0], &mydim[1], fp))
115 goto badheader;
116 if ((mydim[0] == sskip_dim[0]) & (mydim[1] == sskip_dim[1])) {
117 skipin.cf.Y.dstart = ftell(fp);
118 fclose(fp);
119 return; /* lookin' good! */
120 }
121 badheader:
122 sprintf(errmsg, "incompatible header for matrix '%s'", skipin.cfname);
123 error(USER, errmsg);
124 fclose(fp);
125 }
126
127 /* Open a set of bitmaps corresponding to loaded sources w/ corrections */
128 int
129 srcskip_open(char *bmpspec, char *scorrimg)
130 {
131 int bmcnt = 0;
132 char fname[MAXSTR];
133 char *sfx;
134 int sn;
135
136 srcskip_free_maps(); /* clear previous */
137 srcskip_close();
138 sskip_dim[0] = sskip_dim[1] = 0;
139 if (!nsources) {
140 sskip_rsi(NULL);
141 return(0);
142 }
143 if (bmpspec == NULL)
144 return(0);
145 if (strstr(bmpspec, "%s") == NULL)
146 error(USER, "missing '%s' in source skip BMP file spec");
147 if (ssf_select == NULL) /* starting fresh? */
148 ssf_select = sskip_new();
149 if (scorrimg == NULL) /* no correction map? */
150 skipin.cfname[0] = '\0';
151 else
152 strcpy(skipin.cfname, scorrimg);
153 skipin.cftype = CFnone; /* open input BMPs */
154 for (sn = 0; sn < nsources; sn++) {
155 OBJECT mod;
156 const char *modname;
157 SKIPBMP *sbmp;
158 int sn1;
159 if (source[sn].sflags & (SSKIP|SVIRTUAL) ||
160 sskip_chk(ssf_select, sn))
161 continue;
162 mod = source[sn].so->omod;
163 modname = objptr(mod)->oname;
164 sprintf(fname, bmpspec, modname);
165 if (access(fname, R_OK) < 0)
166 continue; /* none such input */
167 /* else check it out */
168 sbmp = (SKIPBMP *)emalloc(sizeof(SKIPBMP)+strlen(fname));
169 strcpy(sbmp->bname, fname);
170 sbmp->bmp = BMPopenInputFile(fname);
171 if (sbmp->bmp == NULL) {
172 sprintf(errmsg, "cannot open bitmap '%s'", fname);
173 error(SYSTEM, errmsg);
174 }
175 if (sbmp->bmp->hdr->nColors > 2) {
176 sprintf(errmsg, "expected bilevel bitmap in '%s'", fname);
177 error(USER, errmsg);
178 }
179 if (!sbmp->bmp->hdr->yIsDown) {
180 sprintf(errmsg, "bad orientation for '%s'", fname);
181 error(INTERNAL, errmsg);
182 }
183 if (skipin.sbmplist == NULL) {
184 sskip_dim[0] = sbmp->bmp->hdr->width;
185 sskip_dim[1] = sbmp->bmp->hdr->height;
186 } else if ((sbmp->bmp->hdr->width != sskip_dim[0]) |
187 (sbmp->bmp->hdr->height != sskip_dim[1])) {
188 sprintf(errmsg, "dimensions do not match for '%s'",
189 fname);
190 error(USER, errmsg);
191 }
192 /* flag this light source */
193 sbmp->sfl = sskip_new();
194 sskip_set(sbmp->sfl, sn);
195 /* flag others w/ same modifier */
196 for (sn1 = sn; ++sn1 < nsources; ) {
197 OBJECT mod1;
198 if (source[sn1].sflags & (SSKIP|SVIRTUAL) ||
199 sskip_chk(ssf_select, sn1))
200 continue;
201 mod1 = source[sn1].so->omod;
202 if (mod1 == mod || !strcmp(objptr(mod1)->oname, modname))
203 sskip_set(sbmp->sfl, sn1);
204 }
205 sskip_addflags(ssf_select, sbmp->sfl);
206 sbmp->next = skipin.sbmplist;
207 skipin.sbmplist = sbmp;
208 bmcnt++;
209 }
210 if (!bmcnt) {
211 sprintf(errmsg, "no matching BMP input files for '%s'", bmpspec);
212 error(WARNING, errmsg);
213 return(0);
214 }
215 if (!skipin.cfname[0]) /* no correction image? */
216 return(bmcnt);
217 /* else open correction image */
218 sfx = skipin.cfname; /* find file type */
219 while (*sfx) sfx++;
220 while (--sfx > skipin.cfname && !ISDIRSEP(*sfx))
221 if (*sfx == '.') {
222 if (!strcasecmp(sfx, ".mtx"))
223 skipin.cftype = CFfloatY;
224 else if (!strcasecmp(sfx, ".bmp"))
225 skipin.cftype = CFbmpY8;
226 break;
227 }
228 switch (skipin.cftype) {
229 case CFfloatY:
230 open_float_mtx();
231 break;
232 case CFbmpY8:
233 skipin.cf.bmp = BMPopenInputFile(skipin.cfname);
234 if (skipin.cf.bmp == NULL) {
235 sprintf(errmsg, "cannot open image '%s'", skipin.cfname);
236 error(SYSTEM, errmsg);
237 }
238 if (!skipin.cf.bmp->hdr->yIsDown |
239 (skipin.cf.bmp->hdr->bpp != 8) |
240 (skipin.cf.bmp->hdr->width != sskip_dim[0]) |
241 (skipin.cf.bmp->hdr->height != sskip_dim[1])) {
242 sprintf(errmsg, "bad type/size/orientation for '%s'",
243 skipin.cfname);
244 error(USER, errmsg);
245 }
246 break;
247 case CFnone:
248 sprintf(errmsg, "unsupported image type for '%s'", skipin.cfname);
249 error(USER, errmsg);
250 }
251 return(bmcnt); /* ready to roll */
252 }
253
254 /* private function to convert 8-bit to float correction multiplier */
255 static void
256 srcskip_cvtY8(float *scorr, const uby8 *y8, int n)
257 {
258 static float gamtab[256];
259
260 if (gamtab[0] < 0.5f) { /* initialize lookup */
261 int i = 256;
262 while (i--)
263 gamtab[i] = 1./(1. - pow((i+.5)*(1./255.), 2.2));
264 }
265 while (n-- > 0)
266 *scorr++ = gamtab[*y8++];
267 }
268
269 /* Read and convert the specified source skip scanline */
270 int
271 srcskip_getrow(int row, int *sndx, float *scorr)
272 {
273 int err;
274
275 if ((0 > row) | (row >= sskip_dim[1]))
276 goto badargum;
277 if (sndx != NULL) { /* read bitmap flags & convert? */
278 uby8 *scanflags;
279 SKIPBMP *sbmp;
280 int x;
281 if (skipin.sbmplist == NULL)
282 goto inpclosed;
283 errno = 0;
284 for (sbmp = skipin.sbmplist; sbmp != NULL; sbmp = sbmp->next)
285 if ((err = BMPseekScanline(row, sbmp->bmp)) != BIR_OK) {
286 sprintf(errmsg, "%s '%s'",
287 BMPerrorMessage(err), sbmp->bname);
288 error(SYSTEM, errmsg);
289 }
290 /* per-column source skip flags */
291 scanflags = (uby8 *)ecalloc(sskip_dim[0], SSKIPFLSIZ);
292 for (sbmp = skipin.sbmplist; sbmp != NULL; sbmp = sbmp->next) {
293 const uby8 *bscn = sbmp->bmp->scanline;
294 for (x = 0; x < sskip_dim[0]; bscn += !(++x & 7))
295 if (!(*bscn & 0x80>>(x&7)))
296 sskip_addflags(scanflags + x*SSKIPFLSIZ,
297 sbmp->sfl);
298 }
299 /* convert to lookup indices */
300 for (x = sskip_dim[0]; x-- > 0; )
301 sndx[x] = sskip_rsi(scanflags + x*SSKIPFLSIZ);
302 efree(scanflags);
303 }
304 if (scorr == NULL) /* all done? */
305 return(row);
306 switch (skipin.cftype) { /* else read correction row */
307 case CFfloatY:
308 if (skipin.cf.Y.fd < 0)
309 goto inpclosed;
310 if (pread(skipin.cf.Y.fd, scorr, sizeof(float)*sskip_dim[0],
311 skipin.cf.Y.dstart + sizeof(float)*sskip_dim[0]*row)
312 != sizeof(float)*sskip_dim[0]) {
313 sprintf(errmsg, "read error from '%s'", skipin.cfname);
314 error(SYSTEM, errmsg);
315 }
316 return(row);
317 case CFbmpY8:
318 if (skipin.cf.bmp == NULL)
319 goto inpclosed;
320 err = BMPseekScanline(row, skipin.cf.bmp);
321 if (err != BIR_OK) {
322 sprintf(errmsg, "%s '%s'",
323 BMPerrorMessage(err), skipin.cfname);
324 error(SYSTEM, errmsg);
325 }
326 srcskip_cvtY8(scorr, skipin.cf.bmp->scanline, sskip_dim[0]);
327 return(row);
328 case CFnone: /* caller asking for missing input */
329 break;
330 }
331 inpclosed:
332 error(CONSISTENCY, "call to srcskip_getrow() on closed input");
333 return(EOF);
334 badargum:
335 error(CONSISTENCY, "bad argument in srcskip_readrow()");
336 return(EOF); /* pro forma */
337 }
338
339 /* Close input images and free memory (leaving any maps) */
340 void
341 srcskip_close()
342 {
343 while (skipin.sbmplist != NULL) {
344 SKIPBMP *sbmp = skipin.sbmplist;
345 skipin.sbmplist = sbmp->next;
346 BMPcloseInput(sbmp->bmp);
347 sskip_free(sbmp->sfl);
348 efree(sbmp);
349 }
350 switch (skipin.cftype) {
351 case CFfloatY:
352 if (skipin.cf.Y.fd >= 0) {
353 close(skipin.cf.Y.fd);
354 skipin.cf.Y.fd = -1;
355 }
356 break;
357 case CFbmpY8:
358 if (skipin.cf.bmp != NULL) {
359 BMPcloseInput(skipin.cf.bmp);
360 skipin.cf.bmp = NULL;
361 }
362 break;
363 }
364 skipin.cfname[0] = '\0';
365 if (ssf_select == NULL) { /* freed lookup table already? */
366 srcskip_free_maps();
367 skipin.cftype = CFnone;
368 sskip_dim[0] = sskip_dim[1] = 0;
369 }
370 }
371
372 #if defined(_WIN32) || defined(_WIN64)
373
374 /* Allocate and load entire source skip index array */
375 int *
376 srcskip_ndxmap()
377 {
378 int y;
379
380 if (ssf_select == NULL) { /* rug pulled from under us? */
381 srcskip_free_maps();
382 return(NULL);
383 }
384 if (skipin.ndxmap != NULL)
385 return(skipin.ndxmap);
386
387 skipin.ndxmap = (int *)emalloc(sizeof(int) *
388 sskip_dim[0]*sskip_dim[1]);
389
390 for (y = 0; y < sskip_dim[1]; y++)
391 srcskip_getrow(y, skipin.ndxmap + sskip_dim[0]*y, NULL);
392
393 return(skipin.ndxmap);
394 }
395
396 /* Allocate and load entire source correction array */
397 float *
398 srcskip_corrmap()
399 {
400 int y;
401 ssize_t nbytes;
402
403 if (ssf_select == NULL) { /* rug pulled from under us? */
404 srcskip_free_maps();
405 return(NULL);
406 }
407 if (skipin.corrmap != NULL)
408 return(skipin.corrmap);
409
410 if (skipin.cftype == CFnone)
411 return(NULL);
412
413 nbytes = sizeof(float)*sskip_dim[0]*sskip_dim[1];
414
415 skipin.corrmap = (float *)emalloc(nbytes);
416
417 switch (skipin.cftype) {
418 case CFfloatY:
419 if (pread(skipin.cf.Y.fd, skipin.corrmap, nbytes,
420 skipin.cf.Y.dstart) != nbytes) {
421 sprintf(errmsg, "read error from '%s'", skipin.cfname);
422 error(SYSTEM, errmsg);
423 }
424 break;
425 case CFbmpY8:
426 for (y = 0; y < sskip_dim[1]; y++)
427 srcskip_getrow(y, NULL, skipin.corrmap + sskip_dim[0]*y);
428 break;
429 }
430 skipin.cref = 1;
431 return(skipin.corrmap);
432 }
433
434 /* Free allocated memory for source skip index and correction maps */
435 void
436 srcskip_free_maps()
437 {
438 efree(skipin.ndxmap); skipin.ndxmap = NULL;
439 efree(skipin.corrmap); skipin.corrmap = NULL;
440 }
441
442 #else /* ! Windows */
443
444 #include <sys/mman.h> /* mmap() support */
445
446 /* Create memory map with entire source skip index array */
447 int *
448 srcskip_ndxmap()
449 {
450 int y;
451
452 if (ssf_select == NULL) { /* rug pulled from under us? */
453 srcskip_free_maps();
454 return(NULL);
455 }
456 if (skipin.ndxmap != NULL)
457 return(skipin.ndxmap);
458
459 skipin.ndxmap = (int *)mmap(NULL, sizeof(int)*sskip_dim[0]*sskip_dim[1],
460 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
461
462 if ((void *)skipin.ndxmap == MAP_FAILED)
463 error(SYSTEM, "out of memory in srcskip_ndxmap()");
464
465 for (y = 0; y < sskip_dim[1]; y++)
466 srcskip_getrow(y, skipin.ndxmap + sskip_dim[0]*y, NULL);
467
468 return(skipin.ndxmap);
469 }
470
471 /* Create memory map with entire source skip correction array */
472 float *
473 srcskip_corrmap()
474 {
475 int y;
476 ssize_t nbytes;
477
478 if (ssf_select == NULL) { /* rug pulled from under us? */
479 srcskip_free_maps();
480 return(NULL);
481 }
482 if (skipin.corrmap != NULL)
483 return(skipin.corrmap);
484
485 if (skipin.cftype == CFnone)
486 return(NULL);
487
488 nbytes = sizeof(float)*sskip_dim[0]*sskip_dim[1];
489
490 if (skipin.cftype != CFfloatY || skipin.cf.Y.dstart % sizeof(float)) {
491 skipin.corrmap = (float *)mmap(NULL, nbytes,
492 PROT_READ|PROT_WRITE,
493 MAP_ANON|MAP_PRIVATE, -1, 0);
494 if ((void *)skipin.corrmap == MAP_FAILED)
495 error(SYSTEM, "out of memory in srcskip_corrmap()");
496 }
497 switch (skipin.cftype) {
498 case CFfloatY:
499 if (skipin.corrmap != NULL) {
500 if (pread(skipin.cf.Y.fd, skipin.corrmap, nbytes,
501 skipin.cf.Y.dstart) != nbytes) {
502 sprintf(errmsg, "read error from '%s'",
503 skipin.cfname);
504 error(SYSTEM, errmsg);
505 }
506 break; /* best we could do */
507 } /* else map directly to file data */
508 skipin.corrmap = (float *)mmap(NULL, skipin.cf.Y.dstart + nbytes,
509 PROT_READ|PROT_WRITE,
510 MAP_FILE|MAP_PRIVATE, skipin.cf.Y.fd, 0);
511 if ((void *)skipin.corrmap == MAP_FAILED)
512 error(SYSTEM, "cannot map file in srcskip_corrmap()");
513 skipin.corrmap += skipin.cf.Y.dstart/sizeof(float);
514 break;
515 case CFbmpY8:
516 for (y = 0; y < sskip_dim[1]; y++)
517 srcskip_getrow(y, NULL, skipin.corrmap + sskip_dim[0]*y);
518 break;
519 }
520 return(skipin.corrmap);
521 }
522
523 /* Unmap memory allocated for source skip index and correction arrays */
524 void
525 srcskip_free_maps()
526 {
527 if (skipin.ndxmap != NULL) {
528 munmap(skipin.ndxmap, sizeof(int)*sskip_dim[0]*sskip_dim[1]);
529 skipin.ndxmap = NULL;
530 }
531 if (skipin.corrmap != NULL) {
532 off_t headlen = 0;
533 if (skipin.cftype == CFfloatY &&
534 !(skipin.cf.Y.dstart % sizeof(float)))
535 headlen = skipin.cf.Y.dstart;
536
537 munmap((char *)skipin.corrmap - headlen,
538 headlen + sizeof(float)*sskip_dim[0]*sskip_dim[1]);
539 skipin.corrmap = NULL;
540 }
541 }
542
543 #endif /* ! Windows */
544 #endif /* SSKIPOPT */