| 10 |  | #include <string.h> | 
| 11 |  | #include <fcntl.h> | 
| 12 |  | #include "resolu.h" | 
| 13 | + | #include "rtprocess.h" | 
| 14 |  | #include "rmatrix.h" | 
| 15 |  |  | 
| 16 | < | typedef struct { | 
| 16 | < | int     nrows, ncols, ncomp; | 
| 17 | < | int     dtype; | 
| 18 | < | } DMINFO; | 
| 16 | > | static char     rmx_mismatch_warn[] = "WARNING: data type mismatch\n"; | 
| 17 |  |  | 
| 18 |  | /* Allocate a nr x nc matrix with n components */ | 
| 19 |  | RMATRIX * | 
| 28 |  | if (dnew == NULL) | 
| 29 |  | return(NULL); | 
| 30 |  | dnew->nrows = nr; dnew->ncols = nc; dnew->ncomp = n; | 
| 31 | + | dnew->dtype = DTdouble; | 
| 32 | + | dnew->info = NULL; | 
| 33 |  | return(dnew); | 
| 34 |  | } | 
| 35 |  |  | 
| 36 | + | /* Free a RMATRIX array */ | 
| 37 | + | void | 
| 38 | + | rmx_free(RMATRIX *rm) | 
| 39 | + | { | 
| 40 | + | if (!rm) return; | 
| 41 | + | if (rm->info) | 
| 42 | + | free(rm->info); | 
| 43 | + | free(rm); | 
| 44 | + | } | 
| 45 | + |  | 
| 46 | + | /* Resolve data type based on two input types (returns 0 for mismatch) */ | 
| 47 | + | int | 
| 48 | + | rmx_newtype(int dtyp1, int dtyp2) | 
| 49 | + | { | 
| 50 | + | if ((dtyp1==DTxyze) | (dtyp1==DTrgbe) | | 
| 51 | + | (dtyp2==DTxyze) | (dtyp2==DTrgbe) | 
| 52 | + | && dtyp1 != dtyp2) | 
| 53 | + | return(0); | 
| 54 | + | if (dtyp1 < dtyp2) | 
| 55 | + | return(dtyp1); | 
| 56 | + | return(dtyp2); | 
| 57 | + | } | 
| 58 | + |  | 
| 59 | + | /* Append header information associated with matrix data */ | 
| 60 | + | int | 
| 61 | + | rmx_addinfo(RMATRIX *rm, const char *info) | 
| 62 | + | { | 
| 63 | + | if (!info || !*info) | 
| 64 | + | return(0); | 
| 65 | + | if (!rm->info) { | 
| 66 | + | rm->info = (char *)malloc(strlen(info)+1); | 
| 67 | + | if (rm->info) rm->info[0] = '\0'; | 
| 68 | + | } else | 
| 69 | + | rm->info = (char *)realloc(rm->info, | 
| 70 | + | strlen(rm->info)+strlen(info)+1); | 
| 71 | + | if (!rm->info) | 
| 72 | + | return(0); | 
| 73 | + | strcat(rm->info, info); | 
| 74 | + | return(1); | 
| 75 | + | } | 
| 76 | + |  | 
| 77 |  | static int | 
| 78 |  | get_dminfo(char *s, void *p) | 
| 79 |  | { | 
| 80 | < | DMINFO  *ip = (DMINFO *)p; | 
| 81 | < | char    fmt[32]; | 
| 80 | > | RMATRIX *ip = (RMATRIX *)p; | 
| 81 | > | char    fmt[64]; | 
| 82 |  | int     i; | 
| 83 |  |  | 
| 84 | + | if (headidval(fmt, s)) | 
| 85 | + | return(0); | 
| 86 |  | if (!strncmp(s, "NCOMP=", 6)) { | 
| 87 |  | ip->ncomp = atoi(s+6); | 
| 88 |  | return(0); | 
| 95 |  | ip->ncols = atoi(s+6); | 
| 96 |  | return(0); | 
| 97 |  | } | 
| 98 | < | if (!formatval(fmt, s)) | 
| 98 | > | if (!formatval(fmt, s)) { | 
| 99 | > | rmx_addinfo(ip, s); | 
| 100 |  | return(0); | 
| 101 | + | } | 
| 102 |  | for (i = 1; i < DTend; i++) | 
| 103 |  | if (!strcmp(fmt, cm_fmt_id[i])) { | 
| 104 |  | ip->dtype = i; | 
| 111 |  | rmx_load_ascii(RMATRIX *rm, FILE *fp) | 
| 112 |  | { | 
| 113 |  | int     i, j, k; | 
| 114 | < | #ifdef _WIN32 | 
| 70 | < | _setmode(fileno(fp), _O_TEXT); | 
| 71 | < | #endif | 
| 114 | > |  | 
| 115 |  | for (i = 0; i < rm->nrows; i++) | 
| 116 |  | for (j = 0; j < rm->ncols; j++) | 
| 117 |  | for (k = 0; k < rm->ncomp; k++) | 
| 185 |  |  | 
| 186 |  | /* Load matrix from supported file type */ | 
| 187 |  | RMATRIX * | 
| 188 | < | rmx_load(const char *fname) | 
| 188 | > | rmx_load(const char *inspec) | 
| 189 |  | { | 
| 190 |  | FILE            *fp = stdin; | 
| 191 | < | DMINFO          dinfo; | 
| 191 | > | RMATRIX         dinfo; | 
| 192 |  | RMATRIX         *dnew; | 
| 193 |  |  | 
| 194 | < | if (fname == NULL) {                    /* reading from stdin? */ | 
| 195 | < | fname = "<stdin>"; | 
| 194 | > | if (inspec == NULL) {                   /* reading from stdin? */ | 
| 195 | > | inspec = "<stdin>"; | 
| 196 | > | #ifdef _WIN32 | 
| 197 | > | _setmode(fileno(stdin), _O_BINARY); | 
| 198 | > | #endif | 
| 199 | > | } else if (inspec[0] == '!') { | 
| 200 | > | if ((fp = popen(inspec+1, "r")) == NULL) | 
| 201 | > | return(NULL); | 
| 202 | > | #ifdef _WIN32 | 
| 203 | > | _setmode(fileno(fp), _O_BINARY); | 
| 204 | > | #endif | 
| 205 |  | } else { | 
| 206 | < | const char      *sp = fname;    /* check suffix */ | 
| 206 | > | const char      *sp = inspec;   /* check suffix */ | 
| 207 |  | while (*sp) | 
| 208 |  | ++sp; | 
| 209 | < | while (sp > fname && sp[-1] != '.') | 
| 209 | > | while (sp > inspec && sp[-1] != '.') | 
| 210 |  | --sp; | 
| 211 |  | if (!strcasecmp(sp, "XML")) {   /* assume it's a BSDF */ | 
| 212 | < | CMATRIX *cm = cm_loadBTDF((char *)fname); | 
| 212 | > | CMATRIX *cm = cm_loadBTDF((char *)inspec); | 
| 213 |  | if (cm == NULL) | 
| 214 |  | return(NULL); | 
| 215 |  | dnew = rmx_from_cmatrix(cm); | 
| 216 |  | cm_free(cm); | 
| 217 | + | dnew->dtype = DTascii; | 
| 218 |  | return(dnew); | 
| 219 |  | } | 
| 220 |  | /* else open it ourselves */ | 
| 221 | < | if ((fp = fopen(fname, "rb")) == NULL) | 
| 221 | > | if ((fp = fopen(inspec, "rb")) == NULL) | 
| 222 |  | return(NULL); | 
| 223 |  | } | 
| 224 |  | #ifdef getc_unlocked | 
| 225 |  | flockfile(fp); | 
| 226 |  | #endif | 
| 227 |  | dinfo.nrows = dinfo.ncols = dinfo.ncomp = 0; | 
| 228 | < | dinfo.dtype = DTascii; | 
| 228 | > | dinfo.dtype = DTascii;                  /* assumed w/o FORMAT */ | 
| 229 | > | dinfo.info = NULL; | 
| 230 |  | if (getheader(fp, get_dminfo, &dinfo) < 0) { | 
| 231 |  | fclose(fp); | 
| 232 |  | return(NULL); | 
| 233 |  | } | 
| 234 | < | if ((dinfo.dtype == DTrgbe) | (dinfo.dtype == DTxyze)) { | 
| 234 | > | if ((dinfo.nrows <= 0) | (dinfo.ncols <= 0)) { | 
| 235 |  | if (!fscnresolu(&dinfo.ncols, &dinfo.nrows, fp)) { | 
| 236 |  | fclose(fp); | 
| 237 |  | return(NULL); | 
| 238 |  | } | 
| 239 | < | dinfo.ncomp = 3; | 
| 239 | > | if (dinfo.ncomp <= 0) | 
| 240 | > | dinfo.ncomp = 3; | 
| 241 | > | else if ((dinfo.dtype == DTrgbe) | (dinfo.dtype == DTxyze) && | 
| 242 | > | dinfo.ncomp != 3) { | 
| 243 | > | fclose(fp); | 
| 244 | > | return(NULL); | 
| 245 | > | } | 
| 246 |  | } | 
| 247 |  | dnew = rmx_alloc(dinfo.nrows, dinfo.ncols, dinfo.ncomp); | 
| 248 |  | if (dnew == NULL) { | 
| 249 |  | fclose(fp); | 
| 250 |  | return(NULL); | 
| 251 |  | } | 
| 252 | + | dnew->info = dinfo.info; | 
| 253 |  | switch (dinfo.dtype) { | 
| 254 |  | case DTascii: | 
| 255 | + | #ifdef _WIN32 | 
| 256 | + | _setmode(fileno(fp), _O_TEXT); | 
| 257 | + | #endif | 
| 258 |  | if (!rmx_load_ascii(dnew, fp)) | 
| 259 |  | goto loaderr; | 
| 260 | + | dnew->dtype = DTascii;          /* should leave double? */ | 
| 261 |  | break; | 
| 262 |  | case DTfloat: | 
| 263 |  | if (!rmx_load_float(dnew, fp)) | 
| 264 |  | goto loaderr; | 
| 265 | + | dnew->dtype = DTfloat; | 
| 266 |  | break; | 
| 267 |  | case DTdouble: | 
| 268 |  | if (!rmx_load_double(dnew, fp)) | 
| 269 |  | goto loaderr; | 
| 270 | + | dnew->dtype = DTdouble; | 
| 271 |  | break; | 
| 272 |  | case DTrgbe: | 
| 273 |  | case DTxyze: | 
| 274 |  | if (!rmx_load_rgbe(dnew, fp)) | 
| 275 |  | goto loaderr; | 
| 276 | + | dnew->dtype = dinfo.dtype; | 
| 277 |  | break; | 
| 278 |  | default: | 
| 279 |  | goto loaderr; | 
| 280 |  | } | 
| 281 | < | if (fp != stdin) | 
| 282 | < | fclose(fp); | 
| 281 | > | if (fp != stdin) { | 
| 282 | > | if (inspec[0] == '!') | 
| 283 | > | pclose(fp); | 
| 284 | > | else | 
| 285 | > | fclose(fp); | 
| 286 | > | } | 
| 287 | > | #ifdef getc_unlocked | 
| 288 | > | else | 
| 289 | > | funlockfile(fp); | 
| 290 | > | #endif | 
| 291 |  | return(dnew); | 
| 292 |  | loaderr:                                        /* should report error? */ | 
| 293 | < | fclose(fp); | 
| 293 | > | if (inspec[0] == '!') | 
| 294 | > | pclose(fp); | 
| 295 | > | else | 
| 296 | > | fclose(fp); | 
| 297 |  | rmx_free(dnew); | 
| 298 |  | return(NULL); | 
| 299 |  | } | 
| 302 |  | rmx_write_ascii(const RMATRIX *rm, FILE *fp) | 
| 303 |  | { | 
| 304 |  | int     i, j, k; | 
| 305 | < | #ifdef _WIN32 | 
| 227 | < | _setmode(fileno(fp), _O_TEXT); | 
| 228 | < | #endif | 
| 305 | > |  | 
| 306 |  | for (i = 0; i < rm->nrows; i++) { | 
| 307 |  | for (j = 0; j < rm->ncols; j++) { | 
| 308 |  | for (k = 0; k < rm->ncomp; k++) | 
| 376 |  | return(1); | 
| 377 |  | } | 
| 378 |  |  | 
| 379 | < | /* Write matrix to file type indicated by dt */ | 
| 380 | < | long | 
| 379 | > | /* Write matrix to file type indicated by dtype */ | 
| 380 | > | int | 
| 381 |  | rmx_write(const RMATRIX *rm, int dtype, FILE *fp) | 
| 382 |  | { | 
| 383 |  | RMATRIX *mydm = NULL; | 
| 385 |  |  | 
| 386 |  | if ((rm == NULL) | (fp == NULL)) | 
| 387 |  | return(0); | 
| 388 | + | #ifdef getc_unlocked | 
| 389 | + | flockfile(fp); | 
| 390 | + | #endif | 
| 391 |  | /* complete header */ | 
| 392 | + | if (rm->info) | 
| 393 | + | fputs(rm->info, fp); | 
| 394 | + | if (dtype == DTfromHeader) | 
| 395 | + | dtype = rm->dtype; | 
| 396 | + | else if ((dtype == DTrgbe) & (rm->dtype == DTxyze)) | 
| 397 | + | dtype = DTxyze; | 
| 398 | + | else if ((dtype == DTxyze) & (rm->dtype == DTrgbe)) | 
| 399 | + | dtype = DTrgbe; | 
| 400 |  | if ((dtype != DTrgbe) & (dtype != DTxyze)) { | 
| 401 |  | fprintf(fp, "NROWS=%d\n", rm->nrows); | 
| 402 |  | fprintf(fp, "NCOLS=%d\n", rm->ncols); | 
| 432 |  | return(0); | 
| 433 |  | } | 
| 434 |  | ok &= (fflush(fp) == 0); | 
| 435 | + | #ifdef getc_unlocked | 
| 436 | + | funlockfile(fp); | 
| 437 | + | #endif | 
| 438 |  | rmx_free(mydm); | 
| 439 | < | return(ftell(fp) * ok);         /* return # bytes written */ | 
| 439 | > | return(ok); | 
| 440 |  | } | 
| 441 |  |  | 
| 442 |  | /* Allocate and assign square identity matrix with n components */ | 
| 444 |  | rmx_identity(const int dim, const int n) | 
| 445 |  | { | 
| 446 |  | RMATRIX *rid = rmx_alloc(dim, dim, n); | 
| 447 | < | int     i; | 
| 447 | > | int     i, k; | 
| 448 |  |  | 
| 449 |  | if (rid == NULL) | 
| 450 |  | return(NULL); | 
| 451 | < | memset(rid->mtx, 0, sizeof(rid->mtx[0])*dim*dim); | 
| 451 | > | memset(rid->mtx, 0, sizeof(rid->mtx[0])*n*dim*dim); | 
| 452 |  | for (i = dim; i--; ) | 
| 453 | < | rmx_lval(rid,i,i,0) = 1; | 
| 454 | < | for (i = n; --i; ) | 
| 364 | < | memcpy(rid->mtx+i*(dim*dim), rid->mtx, | 
| 365 | < | sizeof(rid->mtx[0])*dim*dim); | 
| 453 | > | for (k = n; k--; ) | 
| 454 | > | rmx_lval(rid,i,i,k) = 1; | 
| 455 |  | return(rid); | 
| 456 |  | } | 
| 457 |  |  | 
| 466 |  | dnew = rmx_alloc(rm->nrows, rm->ncols, rm->ncomp); | 
| 467 |  | if (dnew == NULL) | 
| 468 |  | return(NULL); | 
| 469 | + | rmx_addinfo(dnew, rm->info); | 
| 470 | + | dnew->dtype = rm->dtype; | 
| 471 |  | memcpy(dnew->mtx, rm->mtx, | 
| 472 |  | sizeof(rm->mtx[0])*rm->ncomp*rm->nrows*rm->ncols); | 
| 473 |  | return(dnew); | 
| 485 |  | dnew = rmx_alloc(rm->ncols, rm->nrows, rm->ncomp); | 
| 486 |  | if (dnew == NULL) | 
| 487 |  | return(NULL); | 
| 488 | + | if (rm->info) { | 
| 489 | + | rmx_addinfo(dnew, rm->info); | 
| 490 | + | rmx_addinfo(dnew, "Transposed rows and columns\n"); | 
| 491 | + | } | 
| 492 | + | dnew->dtype = rm->dtype; | 
| 493 |  | for (i = dnew->nrows; i--; ) | 
| 494 |  | for (j = dnew->ncols; j--; ) | 
| 495 |  | for (k = dnew->ncomp; k--; ) | 
| 510 |  | mres = rmx_alloc(m1->nrows, m2->ncols, m1->ncomp); | 
| 511 |  | if (mres == NULL) | 
| 512 |  | return(NULL); | 
| 513 | + | i = rmx_newtype(m1->dtype, m2->dtype); | 
| 514 | + | if (i) | 
| 515 | + | mres->dtype = i; | 
| 516 | + | else | 
| 517 | + | rmx_addinfo(mres, rmx_mismatch_warn); | 
| 518 |  | for (i = mres->nrows; i--; ) | 
| 519 |  | for (j = mres->ncols; j--; ) | 
| 520 | < | for (h = m1->ncols; h--; ) { | 
| 520 | > | for (k = mres->ncomp; k--; ) { | 
| 521 |  | long double d = 0; | 
| 522 | < | for (k = mres->ncomp; k--; ) | 
| 523 | < | d += (long double)rmx_lval(m1,i,h,k) * | 
| 423 | < | (long double)rmx_lval(m2,h,j,k); | 
| 522 | > | for (h = m1->ncols; h--; ) | 
| 523 | > | d += rmx_lval(m1,i,h,k) * rmx_lval(m2,h,j,k); | 
| 524 |  | rmx_lval(mres,i,j,k) = (double)d; | 
| 525 |  | } | 
| 526 |  | return(mres); | 
| 546 |  | mysf[k] = 1; | 
| 547 |  | sf = mysf; | 
| 548 |  | } | 
| 549 | + | i = rmx_newtype(msum->dtype, madd->dtype); | 
| 550 | + | if (i) | 
| 551 | + | msum->dtype = i; | 
| 552 | + | else | 
| 553 | + | rmx_addinfo(msum, rmx_mismatch_warn); | 
| 554 |  | for (i = msum->nrows; i--; ) | 
| 555 |  | for (j = msum->ncols; j--; ) | 
| 556 |  | for (k = msum->ncomp; k--; ) | 
| 588 |  | dnew = rmx_alloc(msrc->nrows, msrc->ncols, n); | 
| 589 |  | if (dnew == NULL) | 
| 590 |  | return(NULL); | 
| 591 | + | dnew->dtype = msrc->dtype; | 
| 592 |  | for (i = dnew->nrows; i--; ) | 
| 593 |  | for (j = dnew->ncols; j--; ) | 
| 594 |  | for (kd = dnew->ncomp; kd--; ) { | 
| 612 |  | dnew = rmx_alloc(cm->nrows, cm->ncols, 3); | 
| 613 |  | if (dnew == NULL) | 
| 614 |  | return(NULL); | 
| 615 | + | dnew->dtype = DTfloat; | 
| 616 |  | for (i = dnew->nrows; i--; ) | 
| 617 |  | for (j = dnew->ncols; j--; ) { | 
| 618 |  | const COLORV    *cv = cm_lval(cm,i,j); |