ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/Development/ray/src/rt/srcskipload.c
Revision: 2.1
Committed: Fri Nov 15 20:47:42 2024 UTC (13 months, 2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
feat(rpict): Experimental source skipping option with -DSSKIPOPT compile flag

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id$";
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 badargum:
334 error(CONSISTENCY, "bad argument in srcskip_readrow()");
335 return(EOF); /* pro forma */
336 }
337
338 /* Close input images and free memory (leaving any maps) */
339 void
340 srcskip_close()
341 {
342 while (skipin.sbmplist != NULL) {
343 SKIPBMP *sbmp = skipin.sbmplist;
344 skipin.sbmplist = sbmp->next;
345 BMPcloseInput(sbmp->bmp);
346 sskip_free(sbmp->sfl);
347 efree(sbmp);
348 }
349 switch (skipin.cftype) {
350 case CFfloatY:
351 if (skipin.cf.Y.fd >= 0) {
352 close(skipin.cf.Y.fd);
353 skipin.cf.Y.fd = -1;
354 }
355 break;
356 case CFbmpY8:
357 if (skipin.cf.bmp != NULL) {
358 BMPcloseInput(skipin.cf.bmp);
359 skipin.cf.bmp = NULL;
360 }
361 break;
362 }
363 skipin.cfname[0] = '\0';
364 if (ssf_select == NULL) { /* freed lookup table already? */
365 srcskip_free_maps();
366 skipin.cftype = CFnone;
367 sskip_dim[0] = sskip_dim[1] = 0;
368 }
369 }
370
371 #if defined(_WIN32) || defined(_WIN64)
372
373 /* Allocate and load entire source skip index array */
374 int *
375 srcskip_ndxmap()
376 {
377 int y;
378
379 if (ssf_select == NULL) { /* rug pulled from under us? */
380 srcskip_free_maps();
381 return(NULL);
382 }
383 if (skipin.ndxmap != NULL)
384 return(skipin.ndxmap);
385
386 skipin.ndxmap = (int *)emalloc(sizeof(int) *
387 sskip_dim[0]*sskip_dim[1]);
388
389 for (y = 0; y < sskip_dim[1]; y++)
390 srcskip_getrow(y, skipin.ndxmap + sskip_dim[0]*y, NULL);
391
392 return(skipin.ndxmap);
393 }
394
395 /* Allocate and load entire source correction array */
396 float *
397 srcskip_corrmap()
398 {
399 int y;
400 ssize_t nbytes;
401
402 if (ssf_select == NULL) { /* rug pulled from under us? */
403 srcskip_free_maps();
404 return(NULL);
405 }
406 if (skipin.corrmap != NULL)
407 return(skipin.corrmap);
408
409 if (skipin.cftype == CFnone)
410 return(NULL);
411
412 nbytes = sizeof(float)*sskip_dim[0]*sskip_dim[1];
413
414 skipin.corrmap = (float *)emalloc(nbytes);
415
416 switch (skipin.cftype) {
417 case CFfloatY:
418 if (pread(skipin.cf.Y.fd, skipin.corrmap, nbytes,
419 skipin.cf.Y.dstart) != nbytes) {
420 sprintf(errmsg, "read error from '%s'", skipin.cfname);
421 error(SYSTEM, errmsg);
422 }
423 break;
424 case CFbmpY8:
425 for (y = 0; y < sskip_dim[1]; y++)
426 srcskip_getrow(y, NULL, skipin.corrmap + sskip_dim[0]*y);
427 break;
428 }
429 skipin.cref = 1;
430 return(skipin.corrmap);
431 }
432
433 /* Free allocated memory for source skip index and correction maps */
434 void
435 srcskip_free_maps()
436 {
437 efree(skipin.ndxmap); skipin.ndxmap = NULL;
438 efree(skipin.corrmap); skipin.corrmap = NULL;
439 }
440
441 #else /* ! Windows */
442
443 #include <sys/mman.h> /* mmap() support */
444
445 /* Create memory map with entire source skip index array */
446 int *
447 srcskip_ndxmap()
448 {
449 int y;
450
451 if (ssf_select == NULL) { /* rug pulled from under us? */
452 srcskip_free_maps();
453 return(NULL);
454 }
455 if (skipin.ndxmap != NULL)
456 return(skipin.ndxmap);
457
458 skipin.ndxmap = (int *)mmap(NULL, sizeof(int)*sskip_dim[0]*sskip_dim[1],
459 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
460
461 if ((void *)skipin.ndxmap == MAP_FAILED)
462 error(SYSTEM, "out of memory in srcskip_ndxmap()");
463
464 for (y = 0; y < sskip_dim[1]; y++)
465 srcskip_getrow(y, skipin.ndxmap + sskip_dim[0]*y, NULL);
466
467 return(skipin.ndxmap);
468 }
469
470 /* Create memory map with entire source skip correction array */
471 float *
472 srcskip_corrmap()
473 {
474 int y;
475 ssize_t nbytes;
476
477 if (ssf_select == NULL) { /* rug pulled from under us? */
478 srcskip_free_maps();
479 return(NULL);
480 }
481 if (skipin.corrmap != NULL)
482 return(skipin.corrmap);
483
484 if (skipin.cftype == CFnone)
485 return(NULL);
486
487 nbytes = sizeof(float)*sskip_dim[0]*sskip_dim[1];
488
489 if (skipin.cftype != CFfloatY || skipin.cf.Y.dstart % sizeof(float)) {
490 skipin.corrmap = (float *)mmap(NULL, nbytes,
491 PROT_READ|PROT_WRITE,
492 MAP_ANON|MAP_PRIVATE, -1, 0);
493 if ((void *)skipin.corrmap == MAP_FAILED)
494 error(SYSTEM, "out of memory in srcskip_corrmap()");
495 }
496 switch (skipin.cftype) {
497 case CFfloatY:
498 if (skipin.corrmap != NULL) {
499 if (pread(skipin.cf.Y.fd, skipin.corrmap, nbytes,
500 skipin.cf.Y.dstart) != nbytes) {
501 sprintf(errmsg, "read error from '%s'",
502 skipin.cfname);
503 error(SYSTEM, errmsg);
504 }
505 break; /* best we could do */
506 } /* else map directly to file data */
507 skipin.corrmap = (float *)mmap(NULL, skipin.cf.Y.dstart + nbytes,
508 PROT_READ|PROT_WRITE,
509 MAP_FILE|MAP_PRIVATE, skipin.cf.Y.fd, 0);
510 if ((void *)skipin.corrmap == MAP_FAILED)
511 error(SYSTEM, "cannot map file in srcskip_corrmap()");
512 skipin.corrmap += skipin.cf.Y.dstart/sizeof(float);
513 break;
514 case CFbmpY8:
515 for (y = 0; y < sskip_dim[1]; y++)
516 srcskip_getrow(y, NULL, skipin.corrmap + sskip_dim[0]*y);
517 break;
518 }
519 return(skipin.corrmap);
520 }
521
522 /* Unmap memory allocated for source skip index and correction arrays */
523 void
524 srcskip_free_maps()
525 {
526 if (skipin.ndxmap != NULL) {
527 munmap(skipin.ndxmap, sizeof(int)*sskip_dim[0]*sskip_dim[1]);
528 skipin.ndxmap = NULL;
529 }
530 if (skipin.corrmap != NULL) {
531 off_t headlen = 0;
532 if (skipin.cftype == CFfloatY &&
533 !(skipin.cf.Y.dstart % sizeof(float)))
534 headlen = skipin.cf.Y.dstart;
535
536 munmap((char *)skipin.corrmap - headlen,
537 headlen + sizeof(float)*sskip_dim[0]*sskip_dim[1]);
538 skipin.corrmap = NULL;
539 }
540 }
541
542 #endif /* ! Windows */
543 #endif /* SSKIPOPT */