| 1 | 
greg | 
2.1 | 
#ifndef lint | 
| 2 | 
greg | 
2.35 | 
static const char RCSid[] = "$Id: rfluxmtx.c,v 2.34 2016/02/02 18:02:32 greg Exp $"; | 
| 3 | 
greg | 
2.1 | 
#endif | 
| 4 | 
  | 
  | 
/* | 
| 5 | 
  | 
  | 
 * Calculate flux transfer matrix or matrices using rcontrib | 
| 6 | 
  | 
  | 
 */ | 
| 7 | 
  | 
  | 
 | 
| 8 | 
  | 
  | 
#include "copyright.h" | 
| 9 | 
  | 
  | 
 | 
| 10 | 
  | 
  | 
#include <ctype.h> | 
| 11 | 
  | 
  | 
#include <stdlib.h> | 
| 12 | 
  | 
  | 
#include "rtio.h" | 
| 13 | 
  | 
  | 
#include "rtmath.h" | 
| 14 | 
greg | 
2.34 | 
#include "paths.h" | 
| 15 | 
greg | 
2.1 | 
#include "bsdf.h" | 
| 16 | 
  | 
  | 
#include "bsdf_m.h" | 
| 17 | 
  | 
  | 
#include "random.h" | 
| 18 | 
  | 
  | 
#include "triangulate.h" | 
| 19 | 
  | 
  | 
#include "platform.h" | 
| 20 | 
  | 
  | 
 | 
| 21 | 
  | 
  | 
#define MAXRCARG        512 | 
| 22 | 
  | 
  | 
 | 
| 23 | 
  | 
  | 
char            *progname;              /* global argv[0] */ | 
| 24 | 
  | 
  | 
 | 
| 25 | 
greg | 
2.16 | 
int             verbose = 0;            /* verbose mode (< 0 no warnings) */ | 
| 26 | 
greg | 
2.1 | 
 | 
| 27 | 
  | 
  | 
char            *rcarg[MAXRCARG+1] = {"rcontrib", "-fo+"}; | 
| 28 | 
  | 
  | 
int             nrcargs = 2; | 
| 29 | 
  | 
  | 
 | 
| 30 | 
  | 
  | 
const char      overflowerr[] = "%s: too many arguments!\n"; | 
| 31 | 
  | 
  | 
 | 
| 32 | 
  | 
  | 
#define CHECKARGC(n)    if (nrcargs >= MAXRCARG-(n)) \ | 
| 33 | 
  | 
  | 
        { fprintf(stderr, overflowerr, progname); exit(1); } | 
| 34 | 
  | 
  | 
 | 
| 35 | 
greg | 
2.2 | 
int             sampcnt = 0;            /* sample count (0==unset) */ | 
| 36 | 
greg | 
2.1 | 
 | 
| 37 | 
greg | 
2.2 | 
char            *reinhfn = "reinhartb.cal"; | 
| 38 | 
  | 
  | 
char            *shirchiufn = "disk2square.cal"; | 
| 39 | 
greg | 
2.1 | 
char            *kfullfn = "klems_full.cal"; | 
| 40 | 
  | 
  | 
char            *khalffn = "klems_half.cal"; | 
| 41 | 
  | 
  | 
char            *kquarterfn = "klems_quarter.cal"; | 
| 42 | 
  | 
  | 
 | 
| 43 | 
greg | 
2.5 | 
                                        /* string indicating parameters */ | 
| 44 | 
  | 
  | 
const char      PARAMSTART[] = "@rfluxmtx"; | 
| 45 | 
greg | 
2.1 | 
 | 
| 46 | 
  | 
  | 
                                /* surface type IDs */ | 
| 47 | 
  | 
  | 
#define ST_NONE         0 | 
| 48 | 
  | 
  | 
#define ST_POLY         1 | 
| 49 | 
  | 
  | 
#define ST_RING         2 | 
| 50 | 
  | 
  | 
#define ST_SOURCE       3 | 
| 51 | 
  | 
  | 
 | 
| 52 | 
  | 
  | 
typedef struct surf_s { | 
| 53 | 
  | 
  | 
        struct surf_s   *next;          /* next surface in list */ | 
| 54 | 
  | 
  | 
        void            *priv;          /* private data (malloc'ed) */ | 
| 55 | 
  | 
  | 
        char            sname[32];      /* surface name */ | 
| 56 | 
  | 
  | 
        FVECT           snrm;           /* surface normal */ | 
| 57 | 
greg | 
2.4 | 
        double          area;           /* surface area / proj. solid angle */ | 
| 58 | 
greg | 
2.1 | 
        short           styp;           /* surface type */ | 
| 59 | 
greg | 
2.2 | 
        short           nfargs;         /* number of real arguments */ | 
| 60 | 
  | 
  | 
        double          farg[1];        /* real values (extends struct) */ | 
| 61 | 
greg | 
2.1 | 
} SURF;                         /* surface structure */ | 
| 62 | 
  | 
  | 
 | 
| 63 | 
  | 
  | 
typedef struct { | 
| 64 | 
  | 
  | 
        FVECT   uva[2];                 /* tangent axes */ | 
| 65 | 
  | 
  | 
        int     ntris;                  /* number of triangles */ | 
| 66 | 
  | 
  | 
        struct ptri { | 
| 67 | 
  | 
  | 
                float   afrac;                  /* fraction of total area */ | 
| 68 | 
  | 
  | 
                short   vndx[3];                /* vertex indices */ | 
| 69 | 
  | 
  | 
        }       tri[1];                 /* triangle array (extends struct) */ | 
| 70 | 
  | 
  | 
} POLYTRIS;                     /* triangulated polygon */ | 
| 71 | 
  | 
  | 
 | 
| 72 | 
  | 
  | 
typedef struct param_s { | 
| 73 | 
greg | 
2.26 | 
        char            sign;           /* '-' for axis reversal */ | 
| 74 | 
  | 
  | 
        char            hemis[31];      /* hemispherical sampling spec. */ | 
| 75 | 
greg | 
2.1 | 
        int             hsiz;           /* hemisphere basis size */ | 
| 76 | 
  | 
  | 
        int             nsurfs;         /* number of surfaces */ | 
| 77 | 
  | 
  | 
        SURF            *slist;         /* list of surfaces */ | 
| 78 | 
  | 
  | 
        FVECT           vup;            /* up vector (zero if unset) */ | 
| 79 | 
  | 
  | 
        FVECT           nrm;            /* average normal direction */ | 
| 80 | 
greg | 
2.26 | 
        FVECT           udir, vdir;     /* tangent axes */ | 
| 81 | 
greg | 
2.1 | 
        char            *outfn;         /* output file name (receiver) */ | 
| 82 | 
  | 
  | 
        int             (*sample_basis)(struct param_s *p, int, FILE *); | 
| 83 | 
  | 
  | 
} PARAMS;                       /* sender/receiver parameters */ | 
| 84 | 
  | 
  | 
 | 
| 85 | 
  | 
  | 
PARAMS          curparams; | 
| 86 | 
  | 
  | 
char            curmod[128]; | 
| 87 | 
greg | 
2.6 | 
char            newparams[1024]; | 
| 88 | 
greg | 
2.1 | 
 | 
| 89 | 
  | 
  | 
typedef int     SURFSAMP(FVECT, SURF *, double); | 
| 90 | 
  | 
  | 
 | 
| 91 | 
  | 
  | 
static SURFSAMP ssamp_bad, ssamp_poly, ssamp_ring; | 
| 92 | 
  | 
  | 
 | 
| 93 | 
  | 
  | 
SURFSAMP        *orig_in_surf[4] = { | 
| 94 | 
  | 
  | 
                ssamp_bad, ssamp_poly, ssamp_ring, ssamp_bad | 
| 95 | 
  | 
  | 
        }; | 
| 96 | 
  | 
  | 
 | 
| 97 | 
  | 
  | 
/* Clear parameter set */ | 
| 98 | 
  | 
  | 
static void | 
| 99 | 
  | 
  | 
clear_params(PARAMS *p, int reset_only) | 
| 100 | 
  | 
  | 
{ | 
| 101 | 
  | 
  | 
        while (p->slist != NULL) { | 
| 102 | 
  | 
  | 
                SURF    *sdel = p->slist; | 
| 103 | 
  | 
  | 
                p->slist = sdel->next; | 
| 104 | 
  | 
  | 
                if (sdel->priv != NULL) | 
| 105 | 
  | 
  | 
                        free(sdel->priv); | 
| 106 | 
  | 
  | 
                free(sdel); | 
| 107 | 
  | 
  | 
        } | 
| 108 | 
  | 
  | 
        if (reset_only) { | 
| 109 | 
  | 
  | 
                p->nsurfs = 0; | 
| 110 | 
  | 
  | 
                memset(p->nrm, 0, sizeof(FVECT)); | 
| 111 | 
  | 
  | 
                memset(p->vup, 0, sizeof(FVECT)); | 
| 112 | 
  | 
  | 
                p->outfn = NULL; | 
| 113 | 
  | 
  | 
                return; | 
| 114 | 
  | 
  | 
        } | 
| 115 | 
greg | 
2.6 | 
        memset(p, 0, sizeof(PARAMS)); | 
| 116 | 
greg | 
2.1 | 
} | 
| 117 | 
  | 
  | 
 | 
| 118 | 
  | 
  | 
/* Get surface type from name */ | 
| 119 | 
  | 
  | 
static int | 
| 120 | 
  | 
  | 
surf_type(const char *otype) | 
| 121 | 
  | 
  | 
{ | 
| 122 | 
  | 
  | 
        if (!strcmp(otype, "polygon")) | 
| 123 | 
  | 
  | 
                return(ST_POLY); | 
| 124 | 
  | 
  | 
        if (!strcmp(otype, "ring")) | 
| 125 | 
  | 
  | 
                return(ST_RING); | 
| 126 | 
  | 
  | 
        if (!strcmp(otype, "source")) | 
| 127 | 
  | 
  | 
                return(ST_SOURCE); | 
| 128 | 
  | 
  | 
        return(ST_NONE); | 
| 129 | 
  | 
  | 
} | 
| 130 | 
  | 
  | 
 | 
| 131 | 
  | 
  | 
/* Add arguments to oconv command */ | 
| 132 | 
  | 
  | 
static char * | 
| 133 | 
  | 
  | 
oconv_command(int ac, char *av[]) | 
| 134 | 
  | 
  | 
{ | 
| 135 | 
greg | 
2.13 | 
        static char     oconvbuf[2048] = "!oconv -f "; | 
| 136 | 
  | 
  | 
        char            *cp = oconvbuf + 10; | 
| 137 | 
  | 
  | 
        char            *recv = *av++; | 
| 138 | 
  | 
  | 
         | 
| 139 | 
  | 
  | 
        if (ac-- <= 0) | 
| 140 | 
  | 
  | 
                return(NULL); | 
| 141 | 
greg | 
2.1 | 
        while (ac-- > 0) { | 
| 142 | 
greg | 
2.13 | 
                strcpy(cp, *av++); | 
| 143 | 
  | 
  | 
                while (*cp) cp++; | 
| 144 | 
  | 
  | 
                *cp++ = ' '; | 
| 145 | 
greg | 
2.30 | 
                if (cp >= oconvbuf+(sizeof(oconvbuf)-32)) | 
| 146 | 
  | 
  | 
                        goto overrun; | 
| 147 | 
  | 
  | 
        } | 
| 148 | 
  | 
  | 
                                /* receiver goes last */ | 
| 149 | 
  | 
  | 
        if (matchany(recv, SPECIALS)) { | 
| 150 | 
  | 
  | 
                *cp++ = QUOTCHAR; | 
| 151 | 
  | 
  | 
                while (*recv) { | 
| 152 | 
  | 
  | 
                        if (cp >= oconvbuf+(sizeof(oconvbuf)-3)) | 
| 153 | 
  | 
  | 
                                goto overrun; | 
| 154 | 
  | 
  | 
                        *cp++ = *recv++; | 
| 155 | 
greg | 
2.1 | 
                } | 
| 156 | 
greg | 
2.30 | 
                *cp++ = QUOTCHAR; | 
| 157 | 
  | 
  | 
                *cp = '\0'; | 
| 158 | 
  | 
  | 
        } else | 
| 159 | 
  | 
  | 
                strcpy(cp, recv); | 
| 160 | 
greg | 
2.1 | 
        return(oconvbuf); | 
| 161 | 
greg | 
2.30 | 
overrun: | 
| 162 | 
  | 
  | 
        fputs(progname, stderr); | 
| 163 | 
  | 
  | 
        fputs(": too many file arguments!\n", stderr); | 
| 164 | 
  | 
  | 
        exit(1); | 
| 165 | 
greg | 
2.1 | 
} | 
| 166 | 
  | 
  | 
 | 
| 167 | 
  | 
  | 
/* Open a pipe to/from a command given as an argument list */ | 
| 168 | 
  | 
  | 
static FILE * | 
| 169 | 
  | 
  | 
popen_arglist(char *av[], char *mode) | 
| 170 | 
  | 
  | 
{ | 
| 171 | 
  | 
  | 
        char    cmd[10240]; | 
| 172 | 
  | 
  | 
 | 
| 173 | 
  | 
  | 
        if (!convert_commandline(cmd, sizeof(cmd), av)) { | 
| 174 | 
  | 
  | 
                fputs(progname, stderr); | 
| 175 | 
  | 
  | 
                fputs(": command line too long in popen_arglist()\n", stderr); | 
| 176 | 
  | 
  | 
                return(NULL); | 
| 177 | 
  | 
  | 
        } | 
| 178 | 
greg | 
2.16 | 
        if (verbose > 0) | 
| 179 | 
greg | 
2.1 | 
                fprintf(stderr, "%s: opening pipe %s: %s\n", | 
| 180 | 
  | 
  | 
                                progname, (*mode=='w') ? "to" : "from", cmd); | 
| 181 | 
  | 
  | 
        return(popen(cmd, mode)); | 
| 182 | 
  | 
  | 
} | 
| 183 | 
  | 
  | 
 | 
| 184 | 
  | 
  | 
#ifdef _WIN32 | 
| 185 | 
  | 
  | 
/* Execute system command (Windows version) */ | 
| 186 | 
  | 
  | 
static int | 
| 187 | 
  | 
  | 
my_exec(char *av[]) | 
| 188 | 
  | 
  | 
{ | 
| 189 | 
  | 
  | 
        char    cmd[10240]; | 
| 190 | 
  | 
  | 
 | 
| 191 | 
  | 
  | 
        if (!convert_commandline(cmd, sizeof(cmd), av)) { | 
| 192 | 
  | 
  | 
                fputs(progname, stderr); | 
| 193 | 
  | 
  | 
                fputs(": command line too long in my_exec()\n", stderr); | 
| 194 | 
  | 
  | 
                return(1); | 
| 195 | 
  | 
  | 
        } | 
| 196 | 
greg | 
2.16 | 
        if (verbose > 0) | 
| 197 | 
greg | 
2.1 | 
                fprintf(stderr, "%s: running: %s\n", progname, cmd); | 
| 198 | 
  | 
  | 
        return(system(cmd)); | 
| 199 | 
  | 
  | 
} | 
| 200 | 
  | 
  | 
#else | 
| 201 | 
  | 
  | 
/* Execute system command in our stead (Unix version) */ | 
| 202 | 
  | 
  | 
static int | 
| 203 | 
  | 
  | 
my_exec(char *av[]) | 
| 204 | 
  | 
  | 
{ | 
| 205 | 
  | 
  | 
        char    *compath; | 
| 206 | 
  | 
  | 
 | 
| 207 | 
  | 
  | 
        if ((compath = getpath((char *)av[0], getenv("PATH"), X_OK)) == NULL) { | 
| 208 | 
  | 
  | 
                fprintf(stderr, "%s: cannot locate %s\n", progname, av[0]); | 
| 209 | 
  | 
  | 
                return(1); | 
| 210 | 
  | 
  | 
        } | 
| 211 | 
greg | 
2.16 | 
        if (verbose > 0) { | 
| 212 | 
greg | 
2.1 | 
                char    cmd[4096]; | 
| 213 | 
  | 
  | 
                if (!convert_commandline(cmd, sizeof(cmd), av)) | 
| 214 | 
  | 
  | 
                        strcpy(cmd, "COMMAND TOO LONG TO SHOW"); | 
| 215 | 
  | 
  | 
                fprintf(stderr, "%s: running: %s\n", progname, cmd); | 
| 216 | 
  | 
  | 
        } | 
| 217 | 
  | 
  | 
        execv(compath, av);     /* successful call never returns */ | 
| 218 | 
  | 
  | 
        perror(compath); | 
| 219 | 
  | 
  | 
        return(1); | 
| 220 | 
  | 
  | 
} | 
| 221 | 
  | 
  | 
#endif | 
| 222 | 
  | 
  | 
 | 
| 223 | 
  | 
  | 
/* Get normalized direction vector from string specification */ | 
| 224 | 
  | 
  | 
static int | 
| 225 | 
  | 
  | 
get_direction(FVECT dv, const char *s) | 
| 226 | 
  | 
  | 
{ | 
| 227 | 
  | 
  | 
        int     sign = 1; | 
| 228 | 
  | 
  | 
        int     axis = 0; | 
| 229 | 
  | 
  | 
 | 
| 230 | 
  | 
  | 
        memset(dv, 0, sizeof(FVECT)); | 
| 231 | 
  | 
  | 
nextchar: | 
| 232 | 
  | 
  | 
        switch (*s) { | 
| 233 | 
  | 
  | 
        case '+': | 
| 234 | 
  | 
  | 
                ++s; | 
| 235 | 
  | 
  | 
                goto nextchar; | 
| 236 | 
  | 
  | 
        case '-': | 
| 237 | 
  | 
  | 
                sign = -sign; | 
| 238 | 
  | 
  | 
                ++s; | 
| 239 | 
  | 
  | 
                goto nextchar; | 
| 240 | 
  | 
  | 
        case 'z': | 
| 241 | 
  | 
  | 
        case 'Z': | 
| 242 | 
  | 
  | 
                ++axis; | 
| 243 | 
  | 
  | 
        case 'y': | 
| 244 | 
  | 
  | 
        case 'Y': | 
| 245 | 
  | 
  | 
                ++axis; | 
| 246 | 
  | 
  | 
        case 'x': | 
| 247 | 
  | 
  | 
        case 'X': | 
| 248 | 
  | 
  | 
                dv[axis] = sign; | 
| 249 | 
  | 
  | 
                return(!s[1] | isspace(s[1])); | 
| 250 | 
  | 
  | 
        default: | 
| 251 | 
  | 
  | 
                break; | 
| 252 | 
  | 
  | 
        } | 
| 253 | 
  | 
  | 
#ifdef SMLFLT | 
| 254 | 
  | 
  | 
        if (sscanf(s, "%f,%f,%f", &dv[0], &dv[1], &dv[2]) != 3) | 
| 255 | 
  | 
  | 
#else | 
| 256 | 
  | 
  | 
        if (sscanf(s, "%lf,%lf,%lf", &dv[0], &dv[1], &dv[2]) != 3) | 
| 257 | 
  | 
  | 
#endif | 
| 258 | 
  | 
  | 
                return(0); | 
| 259 | 
  | 
  | 
        dv[0] *= (RREAL)sign; | 
| 260 | 
  | 
  | 
        return(normalize(dv) > 0); | 
| 261 | 
  | 
  | 
} | 
| 262 | 
  | 
  | 
 | 
| 263 | 
  | 
  | 
/* Parse program parameters (directives) */ | 
| 264 | 
  | 
  | 
static int | 
| 265 | 
greg | 
2.6 | 
parse_params(PARAMS *p, char *pargs) | 
| 266 | 
greg | 
2.1 | 
{ | 
| 267 | 
  | 
  | 
        char    *cp = pargs; | 
| 268 | 
  | 
  | 
        int     nparams = 0; | 
| 269 | 
greg | 
2.32 | 
        int     quot; | 
| 270 | 
greg | 
2.1 | 
        int     i; | 
| 271 | 
  | 
  | 
 | 
| 272 | 
greg | 
2.15 | 
        for ( ; ; ) { | 
| 273 | 
greg | 
2.1 | 
                switch (*cp++) { | 
| 274 | 
  | 
  | 
                case 'h': | 
| 275 | 
  | 
  | 
                        if (*cp++ != '=') | 
| 276 | 
  | 
  | 
                                break; | 
| 277 | 
greg | 
2.26 | 
                        if ((*cp == '+') | (*cp == '-')) | 
| 278 | 
  | 
  | 
                                p->sign = *cp++; | 
| 279 | 
  | 
  | 
                        else | 
| 280 | 
  | 
  | 
                                p->sign = '+'; | 
| 281 | 
greg | 
2.6 | 
                        p->hsiz = 0; | 
| 282 | 
greg | 
2.1 | 
                        i = 0; | 
| 283 | 
  | 
  | 
                        while (*cp && !isspace(*cp)) { | 
| 284 | 
  | 
  | 
                                if (isdigit(*cp)) | 
| 285 | 
greg | 
2.6 | 
                                        p->hsiz = 10*p->hsiz + *cp - '0'; | 
| 286 | 
  | 
  | 
                                p->hemis[i++] = *cp++; | 
| 287 | 
greg | 
2.1 | 
                        } | 
| 288 | 
  | 
  | 
                        if (!i) | 
| 289 | 
  | 
  | 
                                break; | 
| 290 | 
greg | 
2.6 | 
                        p->hemis[i] = '\0'; | 
| 291 | 
  | 
  | 
                        p->hsiz += !p->hsiz; | 
| 292 | 
greg | 
2.1 | 
                        ++nparams; | 
| 293 | 
  | 
  | 
                        continue; | 
| 294 | 
  | 
  | 
                case 'u': | 
| 295 | 
  | 
  | 
                        if (*cp++ != '=') | 
| 296 | 
  | 
  | 
                                break; | 
| 297 | 
greg | 
2.6 | 
                        if (!get_direction(p->vup, cp)) | 
| 298 | 
greg | 
2.1 | 
                                break; | 
| 299 | 
greg | 
2.15 | 
                        while (*cp && !isspace(*cp++)) | 
| 300 | 
  | 
  | 
                                ; | 
| 301 | 
greg | 
2.1 | 
                        ++nparams; | 
| 302 | 
  | 
  | 
                        continue; | 
| 303 | 
  | 
  | 
                case 'o': | 
| 304 | 
  | 
  | 
                        if (*cp++ != '=') | 
| 305 | 
  | 
  | 
                                break; | 
| 306 | 
greg | 
2.32 | 
                        quot = 0; | 
| 307 | 
  | 
  | 
                        if ((*cp == '"') | (*cp == '\'')) | 
| 308 | 
  | 
  | 
                                quot = *cp++; | 
| 309 | 
greg | 
2.1 | 
                        i = 0; | 
| 310 | 
greg | 
2.32 | 
                        while (*cp && (quot ? (*cp != quot) : !isspace(*cp))) { | 
| 311 | 
  | 
  | 
                                i++; cp++; | 
| 312 | 
  | 
  | 
                        } | 
| 313 | 
greg | 
2.1 | 
                        if (!i) | 
| 314 | 
  | 
  | 
                                break; | 
| 315 | 
greg | 
2.32 | 
                        if (!*cp) { | 
| 316 | 
  | 
  | 
                                if (quot) | 
| 317 | 
  | 
  | 
                                        break; | 
| 318 | 
  | 
  | 
                                cp[1] = '\0'; | 
| 319 | 
  | 
  | 
                        } | 
| 320 | 
  | 
  | 
                        *cp = '\0'; | 
| 321 | 
greg | 
2.6 | 
                        p->outfn = savqstr(cp-i); | 
| 322 | 
greg | 
2.32 | 
                        *cp++ = quot ? quot : ' '; | 
| 323 | 
greg | 
2.1 | 
                        ++nparams; | 
| 324 | 
  | 
  | 
                        continue; | 
| 325 | 
  | 
  | 
                case ' ': | 
| 326 | 
  | 
  | 
                case '\t': | 
| 327 | 
  | 
  | 
                case '\r': | 
| 328 | 
greg | 
2.21 | 
                case '\n': | 
| 329 | 
greg | 
2.15 | 
                        continue; | 
| 330 | 
greg | 
2.1 | 
                case '\0': | 
| 331 | 
  | 
  | 
                        return(nparams); | 
| 332 | 
  | 
  | 
                default: | 
| 333 | 
  | 
  | 
                        break; | 
| 334 | 
  | 
  | 
                } | 
| 335 | 
greg | 
2.15 | 
                break; | 
| 336 | 
  | 
  | 
        } | 
| 337 | 
  | 
  | 
        fprintf(stderr, "%s: bad parameter string: %s", progname, pargs); | 
| 338 | 
greg | 
2.1 | 
        exit(1); | 
| 339 | 
  | 
  | 
        return(-1);     /* pro forma return */ | 
| 340 | 
  | 
  | 
} | 
| 341 | 
  | 
  | 
 | 
| 342 | 
  | 
  | 
/* Add receiver arguments (directives) corresponding to the current modifier */ | 
| 343 | 
  | 
  | 
static void | 
| 344 | 
  | 
  | 
finish_receiver(void) | 
| 345 | 
  | 
  | 
{ | 
| 346 | 
greg | 
2.4 | 
        char    sbuf[256]; | 
| 347 | 
  | 
  | 
        int     uniform = 0; | 
| 348 | 
greg | 
2.2 | 
        char    *calfn = NULL; | 
| 349 | 
greg | 
2.3 | 
        char    *params = NULL; | 
| 350 | 
greg | 
2.2 | 
        char    *binv = NULL; | 
| 351 | 
  | 
  | 
        char    *binf = NULL; | 
| 352 | 
  | 
  | 
        char    *nbins = NULL; | 
| 353 | 
greg | 
2.1 | 
 | 
| 354 | 
  | 
  | 
        if (!curmod[0]) { | 
| 355 | 
  | 
  | 
                fputs(progname, stderr); | 
| 356 | 
  | 
  | 
                fputs(": missing receiver surface!\n", stderr); | 
| 357 | 
  | 
  | 
                exit(1); | 
| 358 | 
  | 
  | 
        } | 
| 359 | 
  | 
  | 
        if (curparams.outfn != NULL) {  /* add output file spec. */ | 
| 360 | 
  | 
  | 
                CHECKARGC(2); | 
| 361 | 
  | 
  | 
                rcarg[nrcargs++] = "-o"; | 
| 362 | 
  | 
  | 
                rcarg[nrcargs++] = curparams.outfn; | 
| 363 | 
  | 
  | 
        } | 
| 364 | 
greg | 
2.4 | 
                                        /* check arguments */ | 
| 365 | 
greg | 
2.1 | 
        if (!curparams.hemis[0]) { | 
| 366 | 
  | 
  | 
                fputs(progname, stderr); | 
| 367 | 
  | 
  | 
                fputs(": missing hemisphere sampling type!\n", stderr); | 
| 368 | 
  | 
  | 
                exit(1); | 
| 369 | 
  | 
  | 
        } | 
| 370 | 
  | 
  | 
        if (normalize(curparams.nrm) == 0) { | 
| 371 | 
  | 
  | 
                fputs(progname, stderr); | 
| 372 | 
  | 
  | 
                fputs(": undefined normal for hemisphere sampling\n", stderr); | 
| 373 | 
  | 
  | 
                exit(1); | 
| 374 | 
  | 
  | 
        } | 
| 375 | 
greg | 
2.10 | 
        if (normalize(curparams.vup) == 0) { | 
| 376 | 
greg | 
2.1 | 
                if (fabs(curparams.nrm[2]) < .7) | 
| 377 | 
  | 
  | 
                        curparams.vup[2] = 1; | 
| 378 | 
  | 
  | 
                else | 
| 379 | 
  | 
  | 
                        curparams.vup[1] = 1; | 
| 380 | 
greg | 
2.10 | 
        } | 
| 381 | 
greg | 
2.4 | 
                                        /* determine sample type/bin */ | 
| 382 | 
greg | 
2.1 | 
        if (tolower(curparams.hemis[0]) == 'u' | curparams.hemis[0] == '1') { | 
| 383 | 
greg | 
2.20 | 
                sprintf(sbuf, "if(-Dx*%g-Dy*%g-Dz*%g,0,-1)", | 
| 384 | 
  | 
  | 
                        curparams.nrm[0], curparams.nrm[1], curparams.nrm[2]); | 
| 385 | 
  | 
  | 
                binv = savqstr(sbuf); | 
| 386 | 
  | 
  | 
                nbins = "1";            /* uniform sampling -- one bin */ | 
| 387 | 
greg | 
2.4 | 
                uniform = 1; | 
| 388 | 
greg | 
2.1 | 
        } else if (tolower(curparams.hemis[0]) == 's' && | 
| 389 | 
  | 
  | 
                                tolower(curparams.hemis[1]) == 'c') { | 
| 390 | 
greg | 
2.2 | 
                                        /* assign parameters */ | 
| 391 | 
greg | 
2.1 | 
                if (curparams.hsiz <= 1) { | 
| 392 | 
  | 
  | 
                        fputs(progname, stderr); | 
| 393 | 
  | 
  | 
                        fputs(": missing size for Shirley-Chiu sampling!\n", stderr); | 
| 394 | 
  | 
  | 
                        exit(1); | 
| 395 | 
  | 
  | 
                } | 
| 396 | 
greg | 
2.3 | 
                calfn = shirchiufn; shirchiufn = NULL; | 
| 397 | 
greg | 
2.26 | 
                sprintf(sbuf, "SCdim=%d,rNx=%g,rNy=%g,rNz=%g,Ux=%g,Uy=%g,Uz=%g,RHS=%c1", | 
| 398 | 
greg | 
2.2 | 
                                curparams.hsiz, | 
| 399 | 
  | 
  | 
                        curparams.nrm[0], curparams.nrm[1], curparams.nrm[2], | 
| 400 | 
greg | 
2.26 | 
                        curparams.vup[0], curparams.vup[1], curparams.vup[2], | 
| 401 | 
  | 
  | 
                        curparams.sign); | 
| 402 | 
greg | 
2.3 | 
                params = savqstr(sbuf); | 
| 403 | 
greg | 
2.2 | 
                binv = "scbin"; | 
| 404 | 
  | 
  | 
                nbins = "SCdim*SCdim"; | 
| 405 | 
greg | 
2.1 | 
        } else if ((tolower(curparams.hemis[0]) == 'r') | | 
| 406 | 
  | 
  | 
                        (tolower(curparams.hemis[0]) == 't')) { | 
| 407 | 
greg | 
2.2 | 
                calfn = reinhfn; reinhfn = NULL; | 
| 408 | 
greg | 
2.26 | 
                sprintf(sbuf, "MF=%d,rNx=%g,rNy=%g,rNz=%g,Ux=%g,Uy=%g,Uz=%g,RHS=%c1", | 
| 409 | 
greg | 
2.3 | 
                                curparams.hsiz, | 
| 410 | 
  | 
  | 
                        curparams.nrm[0], curparams.nrm[1], curparams.nrm[2], | 
| 411 | 
greg | 
2.26 | 
                        curparams.vup[0], curparams.vup[1], curparams.vup[2], | 
| 412 | 
  | 
  | 
                        curparams.sign); | 
| 413 | 
greg | 
2.3 | 
                params = savqstr(sbuf); | 
| 414 | 
  | 
  | 
                binv = "rbin"; | 
| 415 | 
  | 
  | 
                nbins = "Nrbins"; | 
| 416 | 
greg | 
2.1 | 
        } else if (tolower(curparams.hemis[0]) == 'k' && | 
| 417 | 
  | 
  | 
                        !curparams.hemis[1] | | 
| 418 | 
  | 
  | 
                        (tolower(curparams.hemis[1]) == 'f') | | 
| 419 | 
  | 
  | 
                        (curparams.hemis[1] == '1')) { | 
| 420 | 
greg | 
2.2 | 
                calfn = kfullfn; kfullfn = NULL; | 
| 421 | 
  | 
  | 
                binf = "kbin"; | 
| 422 | 
  | 
  | 
                nbins = "Nkbins"; | 
| 423 | 
greg | 
2.1 | 
        } else if (tolower(curparams.hemis[0]) == 'k' && | 
| 424 | 
  | 
  | 
                        (tolower(curparams.hemis[1]) == 'h') | | 
| 425 | 
  | 
  | 
                        (curparams.hemis[1] == '2')) { | 
| 426 | 
greg | 
2.2 | 
                calfn = khalffn; khalffn = NULL; | 
| 427 | 
  | 
  | 
                binf = "khbin"; | 
| 428 | 
  | 
  | 
                nbins = "Nkhbins"; | 
| 429 | 
greg | 
2.1 | 
        } else if (tolower(curparams.hemis[0]) == 'k' && | 
| 430 | 
  | 
  | 
                        (tolower(curparams.hemis[1]) == 'q') | | 
| 431 | 
  | 
  | 
                        (curparams.hemis[1] == '4')) { | 
| 432 | 
greg | 
2.2 | 
                calfn = kquarterfn; kquarterfn = NULL; | 
| 433 | 
  | 
  | 
                binf = "kqbin"; | 
| 434 | 
  | 
  | 
                nbins = "Nkqbins"; | 
| 435 | 
greg | 
2.1 | 
        } else { | 
| 436 | 
  | 
  | 
                fprintf(stderr, "%s: unrecognized hemisphere sampling: h=%s\n", | 
| 437 | 
  | 
  | 
                                progname, curparams.hemis); | 
| 438 | 
  | 
  | 
                exit(1); | 
| 439 | 
  | 
  | 
        } | 
| 440 | 
greg | 
2.26 | 
        if (tolower(curparams.hemis[0]) == 'k') { | 
| 441 | 
  | 
  | 
                sprintf(sbuf, "RHS=%c1", curparams.sign); | 
| 442 | 
  | 
  | 
                params = savqstr(sbuf); | 
| 443 | 
  | 
  | 
        } | 
| 444 | 
greg | 
2.4 | 
        if (!uniform & (curparams.slist->styp == ST_SOURCE)) { | 
| 445 | 
  | 
  | 
                SURF    *sp; | 
| 446 | 
  | 
  | 
                for (sp = curparams.slist; sp != NULL; sp = sp->next) | 
| 447 | 
  | 
  | 
                        if (fabs(sp->area - PI) > 1e-3) { | 
| 448 | 
  | 
  | 
                                fprintf(stderr, "%s: source '%s' must be 180-degrees\n", | 
| 449 | 
  | 
  | 
                                                progname, sp->sname); | 
| 450 | 
  | 
  | 
                                exit(1); | 
| 451 | 
  | 
  | 
                        } | 
| 452 | 
  | 
  | 
        } | 
| 453 | 
greg | 
2.2 | 
        if (calfn != NULL) {            /* add cal file if needed */ | 
| 454 | 
  | 
  | 
                CHECKARGC(2); | 
| 455 | 
  | 
  | 
                rcarg[nrcargs++] = "-f"; | 
| 456 | 
  | 
  | 
                rcarg[nrcargs++] = calfn; | 
| 457 | 
  | 
  | 
        } | 
| 458 | 
greg | 
2.3 | 
        if (params != NULL) {           /* parameters _after_ cal file */ | 
| 459 | 
  | 
  | 
                CHECKARGC(2); | 
| 460 | 
  | 
  | 
                rcarg[nrcargs++] = "-p"; | 
| 461 | 
  | 
  | 
                rcarg[nrcargs++] = params; | 
| 462 | 
  | 
  | 
        } | 
| 463 | 
greg | 
2.2 | 
        if (nbins != NULL) {            /* add #bins if set */ | 
| 464 | 
  | 
  | 
                CHECKARGC(2); | 
| 465 | 
  | 
  | 
                rcarg[nrcargs++] = "-bn"; | 
| 466 | 
  | 
  | 
                rcarg[nrcargs++] = nbins; | 
| 467 | 
  | 
  | 
        } | 
| 468 | 
greg | 
2.3 | 
        if (binv != NULL) { | 
| 469 | 
greg | 
2.2 | 
                CHECKARGC(2);           /* assign bin variable */ | 
| 470 | 
  | 
  | 
                rcarg[nrcargs++] = "-b"; | 
| 471 | 
  | 
  | 
                rcarg[nrcargs++] = binv; | 
| 472 | 
  | 
  | 
        } else if (binf != NULL) { | 
| 473 | 
  | 
  | 
                CHECKARGC(2);           /* assign bin function */ | 
| 474 | 
greg | 
2.3 | 
                rcarg[nrcargs++] = "-b"; | 
| 475 | 
greg | 
2.2 | 
                sprintf(sbuf, "%s(%g,%g,%g,%g,%g,%g)", binf, | 
| 476 | 
  | 
  | 
                        curparams.nrm[0], curparams.nrm[1], curparams.nrm[2], | 
| 477 | 
  | 
  | 
                        curparams.vup[0], curparams.vup[1], curparams.vup[2]); | 
| 478 | 
  | 
  | 
                rcarg[nrcargs++] = savqstr(sbuf); | 
| 479 | 
  | 
  | 
        } | 
| 480 | 
  | 
  | 
        CHECKARGC(2);                           /* modifier argument goes last */ | 
| 481 | 
greg | 
2.1 | 
        rcarg[nrcargs++] = "-m"; | 
| 482 | 
  | 
  | 
        rcarg[nrcargs++] = savqstr(curmod); | 
| 483 | 
  | 
  | 
} | 
| 484 | 
  | 
  | 
 | 
| 485 | 
  | 
  | 
/* Make randomly oriented tangent plane axes for given normal direction */ | 
| 486 | 
  | 
  | 
static void | 
| 487 | 
  | 
  | 
make_axes(FVECT uva[2], const FVECT nrm) | 
| 488 | 
  | 
  | 
{ | 
| 489 | 
  | 
  | 
        int     i; | 
| 490 | 
  | 
  | 
 | 
| 491 | 
greg | 
2.29 | 
        if (!getperpendicular(uva[0], nrm, 1)) { | 
| 492 | 
greg | 
2.1 | 
                fputs(progname, stderr); | 
| 493 | 
  | 
  | 
                fputs(": bad surface normal in make_axes!\n", stderr); | 
| 494 | 
  | 
  | 
                exit(1); | 
| 495 | 
  | 
  | 
        } | 
| 496 | 
greg | 
2.19 | 
        fcross(uva[1], nrm, uva[0]); | 
| 497 | 
greg | 
2.1 | 
} | 
| 498 | 
  | 
  | 
 | 
| 499 | 
  | 
  | 
/* Illegal sender surfaces end up here */ | 
| 500 | 
  | 
  | 
static int | 
| 501 | 
  | 
  | 
ssamp_bad(FVECT orig, SURF *sp, double x) | 
| 502 | 
  | 
  | 
{ | 
| 503 | 
  | 
  | 
        fprintf(stderr, "%s: illegal sender surface '%s'\n", | 
| 504 | 
  | 
  | 
                        progname, sp->sname); | 
| 505 | 
  | 
  | 
        return(0); | 
| 506 | 
  | 
  | 
} | 
| 507 | 
  | 
  | 
 | 
| 508 | 
  | 
  | 
/* Generate origin on ring surface from uniform random variable */ | 
| 509 | 
  | 
  | 
static int | 
| 510 | 
  | 
  | 
ssamp_ring(FVECT orig, SURF *sp, double x) | 
| 511 | 
  | 
  | 
{ | 
| 512 | 
  | 
  | 
        FVECT   *uva = (FVECT *)sp->priv; | 
| 513 | 
  | 
  | 
        double  samp2[2]; | 
| 514 | 
  | 
  | 
        double  uv[2]; | 
| 515 | 
  | 
  | 
        int     i; | 
| 516 | 
  | 
  | 
 | 
| 517 | 
  | 
  | 
        if (uva == NULL) {              /* need tangent axes */ | 
| 518 | 
  | 
  | 
                uva = (FVECT *)malloc(sizeof(FVECT)*2); | 
| 519 | 
  | 
  | 
                if (uva == NULL) { | 
| 520 | 
  | 
  | 
                        fputs(progname, stderr); | 
| 521 | 
  | 
  | 
                        fputs(": out of memory in ssamp_ring!\n", stderr); | 
| 522 | 
  | 
  | 
                        return(0); | 
| 523 | 
  | 
  | 
                } | 
| 524 | 
  | 
  | 
                make_axes(uva, sp->snrm); | 
| 525 | 
  | 
  | 
                sp->priv = (void *)uva; | 
| 526 | 
  | 
  | 
        } | 
| 527 | 
  | 
  | 
        SDmultiSamp(samp2, 2, x); | 
| 528 | 
greg | 
2.6 | 
        samp2[0] = sqrt(samp2[0]*sp->area*(1./PI) + sp->farg[6]*sp->farg[6]); | 
| 529 | 
greg | 
2.1 | 
        samp2[1] *= 2.*PI; | 
| 530 | 
  | 
  | 
        uv[0] = samp2[0]*tcos(samp2[1]); | 
| 531 | 
  | 
  | 
        uv[1] = samp2[0]*tsin(samp2[1]); | 
| 532 | 
  | 
  | 
        for (i = 3; i--; ) | 
| 533 | 
  | 
  | 
                orig[i] = sp->farg[i] + uv[0]*uva[0][i] + uv[1]*uva[1][i]; | 
| 534 | 
  | 
  | 
        return(1); | 
| 535 | 
  | 
  | 
} | 
| 536 | 
  | 
  | 
 | 
| 537 | 
  | 
  | 
/* Add triangle to polygon's list (call-back function) */ | 
| 538 | 
  | 
  | 
static int | 
| 539 | 
  | 
  | 
add_triangle(const Vert2_list *tp, int a, int b, int c) | 
| 540 | 
  | 
  | 
{ | 
| 541 | 
  | 
  | 
        POLYTRIS        *ptp = (POLYTRIS *)tp->p; | 
| 542 | 
  | 
  | 
        struct ptri     *trip = ptp->tri + ptp->ntris++; | 
| 543 | 
  | 
  | 
 | 
| 544 | 
  | 
  | 
        trip->vndx[0] = a; | 
| 545 | 
  | 
  | 
        trip->vndx[1] = b; | 
| 546 | 
  | 
  | 
        trip->vndx[2] = c; | 
| 547 | 
  | 
  | 
        return(1); | 
| 548 | 
  | 
  | 
} | 
| 549 | 
  | 
  | 
 | 
| 550 | 
  | 
  | 
/* Generate origin on polygon surface from uniform random variable */ | 
| 551 | 
  | 
  | 
static int | 
| 552 | 
  | 
  | 
ssamp_poly(FVECT orig, SURF *sp, double x) | 
| 553 | 
  | 
  | 
{ | 
| 554 | 
  | 
  | 
        POLYTRIS        *ptp = (POLYTRIS *)sp->priv; | 
| 555 | 
  | 
  | 
        double          samp2[2]; | 
| 556 | 
  | 
  | 
        double          *v0, *v1, *v2; | 
| 557 | 
  | 
  | 
        int             i; | 
| 558 | 
  | 
  | 
 | 
| 559 | 
  | 
  | 
        if (ptp == NULL) {              /* need to triangulate */ | 
| 560 | 
  | 
  | 
                ptp = (POLYTRIS *)malloc(sizeof(POLYTRIS) + | 
| 561 | 
  | 
  | 
                                sizeof(struct ptri)*(sp->nfargs/3 - 3)); | 
| 562 | 
  | 
  | 
                if (ptp == NULL) | 
| 563 | 
  | 
  | 
                        goto memerr; | 
| 564 | 
  | 
  | 
                if (sp->nfargs == 3) {  /* simple case */ | 
| 565 | 
  | 
  | 
                        ptp->ntris = 1; | 
| 566 | 
  | 
  | 
                        ptp->tri[0].vndx[0] = 0; | 
| 567 | 
  | 
  | 
                        ptp->tri[0].vndx[1] = 1; | 
| 568 | 
  | 
  | 
                        ptp->tri[0].vndx[2] = 2; | 
| 569 | 
  | 
  | 
                        ptp->tri[0].afrac = 1; | 
| 570 | 
  | 
  | 
                } else { | 
| 571 | 
  | 
  | 
                        Vert2_list      *v2l = polyAlloc(sp->nfargs/3); | 
| 572 | 
  | 
  | 
                        if (v2l == NULL) | 
| 573 | 
  | 
  | 
                                goto memerr; | 
| 574 | 
  | 
  | 
                        make_axes(ptp->uva, sp->snrm); | 
| 575 | 
  | 
  | 
                        for (i = v2l->nv; i--; ) { | 
| 576 | 
  | 
  | 
                                v2l->v[i].mX = DOT(sp->farg+3*i, ptp->uva[0]); | 
| 577 | 
  | 
  | 
                                v2l->v[i].mY = DOT(sp->farg+3*i, ptp->uva[1]); | 
| 578 | 
  | 
  | 
                        } | 
| 579 | 
  | 
  | 
                        ptp->ntris = 0; | 
| 580 | 
  | 
  | 
                        v2l->p = (void *)ptp; | 
| 581 | 
greg | 
2.7 | 
                        if (!polyTriangulate(v2l, add_triangle)) { | 
| 582 | 
  | 
  | 
                                fprintf(stderr, | 
| 583 | 
  | 
  | 
                                        "%s: cannot triangulate polygon '%s'\n", | 
| 584 | 
  | 
  | 
                                                progname, sp->sname); | 
| 585 | 
greg | 
2.1 | 
                                return(0); | 
| 586 | 
greg | 
2.7 | 
                        } | 
| 587 | 
greg | 
2.1 | 
                        for (i = ptp->ntris; i--; ) { | 
| 588 | 
  | 
  | 
                                int     a = ptp->tri[i].vndx[0]; | 
| 589 | 
  | 
  | 
                                int     b = ptp->tri[i].vndx[1]; | 
| 590 | 
  | 
  | 
                                int     c = ptp->tri[i].vndx[2]; | 
| 591 | 
  | 
  | 
                                ptp->tri[i].afrac = | 
| 592 | 
  | 
  | 
                                        (v2l->v[a].mX*v2l->v[b].mY - | 
| 593 | 
  | 
  | 
                                         v2l->v[b].mX*v2l->v[a].mY + | 
| 594 | 
  | 
  | 
                                         v2l->v[b].mX*v2l->v[c].mY - | 
| 595 | 
  | 
  | 
                                         v2l->v[c].mX*v2l->v[b].mY + | 
| 596 | 
  | 
  | 
                                         v2l->v[c].mX*v2l->v[a].mY - | 
| 597 | 
  | 
  | 
                                         v2l->v[a].mX*v2l->v[c].mY) / | 
| 598 | 
  | 
  | 
                                                (2.*sp->area); | 
| 599 | 
  | 
  | 
                        } | 
| 600 | 
  | 
  | 
                        polyFree(v2l); | 
| 601 | 
  | 
  | 
                } | 
| 602 | 
  | 
  | 
                sp->priv = (void *)ptp; | 
| 603 | 
  | 
  | 
        } | 
| 604 | 
  | 
  | 
                                        /* pick triangle by partial area */ | 
| 605 | 
  | 
  | 
        for (i = 0; i < ptp->ntris && x > ptp->tri[i].afrac; i++) | 
| 606 | 
  | 
  | 
                x -= ptp->tri[i].afrac; | 
| 607 | 
  | 
  | 
        SDmultiSamp(samp2, 2, x/ptp->tri[i].afrac); | 
| 608 | 
  | 
  | 
        samp2[0] *= samp2[1] = sqrt(samp2[1]); | 
| 609 | 
  | 
  | 
        samp2[1] = 1. - samp2[1]; | 
| 610 | 
  | 
  | 
        v0 = sp->farg + 3*ptp->tri[i].vndx[0]; | 
| 611 | 
  | 
  | 
        v1 = sp->farg + 3*ptp->tri[i].vndx[1]; | 
| 612 | 
  | 
  | 
        v2 = sp->farg + 3*ptp->tri[i].vndx[2]; | 
| 613 | 
  | 
  | 
        for (i = 3; i--; ) | 
| 614 | 
  | 
  | 
                orig[i] = v0[i] + samp2[0]*(v1[i] - v0[i]) | 
| 615 | 
  | 
  | 
                                + samp2[1]*(v2[i] - v0[i]) ; | 
| 616 | 
  | 
  | 
        return(1); | 
| 617 | 
  | 
  | 
memerr: | 
| 618 | 
  | 
  | 
        fputs(progname, stderr); | 
| 619 | 
  | 
  | 
        fputs(": out of memory in ssamp_poly!\n", stderr); | 
| 620 | 
  | 
  | 
        return(0); | 
| 621 | 
  | 
  | 
} | 
| 622 | 
  | 
  | 
 | 
| 623 | 
  | 
  | 
/* Compute sample origin based on projected areas of sender subsurfaces */ | 
| 624 | 
  | 
  | 
static int | 
| 625 | 
  | 
  | 
sample_origin(PARAMS *p, FVECT orig, const FVECT rdir, double x) | 
| 626 | 
  | 
  | 
{ | 
| 627 | 
  | 
  | 
        static double   *projsa; | 
| 628 | 
  | 
  | 
        static int      nall; | 
| 629 | 
  | 
  | 
        double          tarea = 0; | 
| 630 | 
  | 
  | 
        int             i; | 
| 631 | 
  | 
  | 
        SURF            *sp; | 
| 632 | 
  | 
  | 
                                        /* special case for lone surface */ | 
| 633 | 
  | 
  | 
        if (p->nsurfs == 1) { | 
| 634 | 
  | 
  | 
                sp = p->slist; | 
| 635 | 
greg | 
2.31 | 
                if (DOT(sp->snrm, rdir) >= FTINY) { | 
| 636 | 
greg | 
2.7 | 
                        fprintf(stderr, | 
| 637 | 
  | 
  | 
                                "%s: internal - sample behind sender '%s'\n", | 
| 638 | 
  | 
  | 
                                        progname, sp->sname); | 
| 639 | 
  | 
  | 
                        return(0); | 
| 640 | 
  | 
  | 
                } | 
| 641 | 
greg | 
2.1 | 
                return((*orig_in_surf[sp->styp])(orig, sp, x)); | 
| 642 | 
  | 
  | 
        } | 
| 643 | 
  | 
  | 
        if (p->nsurfs > nall) {         /* (re)allocate surface area cache */ | 
| 644 | 
  | 
  | 
                if (projsa) free(projsa); | 
| 645 | 
  | 
  | 
                projsa = (double *)malloc(sizeof(double)*p->nsurfs); | 
| 646 | 
  | 
  | 
                if (!projsa) return(0); | 
| 647 | 
  | 
  | 
                nall = p->nsurfs; | 
| 648 | 
  | 
  | 
        } | 
| 649 | 
  | 
  | 
                                        /* compute projected areas */ | 
| 650 | 
  | 
  | 
        for (i = 0, sp = p->slist; sp != NULL; i++, sp = sp->next) { | 
| 651 | 
  | 
  | 
                projsa[i] = -DOT(sp->snrm, rdir) * sp->area; | 
| 652 | 
  | 
  | 
                tarea += projsa[i] *= (double)(projsa[i] > FTINY); | 
| 653 | 
  | 
  | 
        } | 
| 654 | 
greg | 
2.7 | 
        if (tarea <= FTINY) {           /* wrong side of sender? */ | 
| 655 | 
  | 
  | 
                fputs(progname, stderr); | 
| 656 | 
  | 
  | 
                fputs(": internal - sample behind all sender elements!\n", | 
| 657 | 
  | 
  | 
                                stderr); | 
| 658 | 
greg | 
2.1 | 
                return(0); | 
| 659 | 
greg | 
2.7 | 
        } | 
| 660 | 
greg | 
2.1 | 
        tarea *= x;                     /* get surface from list */ | 
| 661 | 
  | 
  | 
        for (i = 0, sp = p->slist; tarea > projsa[i]; sp = sp->next) | 
| 662 | 
  | 
  | 
                tarea -= projsa[i++]; | 
| 663 | 
  | 
  | 
        return((*orig_in_surf[sp->styp])(orig, sp, tarea/projsa[i])); | 
| 664 | 
  | 
  | 
} | 
| 665 | 
  | 
  | 
 | 
| 666 | 
  | 
  | 
/* Uniform sample generator */ | 
| 667 | 
  | 
  | 
static int | 
| 668 | 
  | 
  | 
sample_uniform(PARAMS *p, int b, FILE *fp) | 
| 669 | 
  | 
  | 
{ | 
| 670 | 
  | 
  | 
        int     n = sampcnt; | 
| 671 | 
  | 
  | 
        double  samp3[3]; | 
| 672 | 
  | 
  | 
        double  duvw[3]; | 
| 673 | 
  | 
  | 
        FVECT   orig_dir[2]; | 
| 674 | 
  | 
  | 
        int     i; | 
| 675 | 
  | 
  | 
 | 
| 676 | 
  | 
  | 
        if (fp == NULL)                 /* just requesting number of bins? */ | 
| 677 | 
  | 
  | 
                return(1); | 
| 678 | 
  | 
  | 
 | 
| 679 | 
  | 
  | 
        while (n--) {                   /* stratified hemisphere sampling */ | 
| 680 | 
  | 
  | 
                SDmultiSamp(samp3, 3, (n+frandom())/sampcnt); | 
| 681 | 
  | 
  | 
                SDsquare2disk(duvw, samp3[1], samp3[2]); | 
| 682 | 
  | 
  | 
                duvw[2] = -sqrt(1. - duvw[0]*duvw[0] - duvw[1]*duvw[1]); | 
| 683 | 
  | 
  | 
                for (i = 3; i--; ) | 
| 684 | 
  | 
  | 
                        orig_dir[1][i] = duvw[0]*p->udir[i] + | 
| 685 | 
  | 
  | 
                                                duvw[1]*p->vdir[i] + | 
| 686 | 
  | 
  | 
                                                duvw[2]*p->nrm[i] ; | 
| 687 | 
  | 
  | 
                if (!sample_origin(p, orig_dir[0], orig_dir[1], samp3[0])) | 
| 688 | 
  | 
  | 
                        return(0); | 
| 689 | 
  | 
  | 
                if (fwrite(orig_dir, sizeof(FVECT), 2, fp) != 2) | 
| 690 | 
  | 
  | 
                        return(0); | 
| 691 | 
  | 
  | 
        } | 
| 692 | 
  | 
  | 
        return(1); | 
| 693 | 
  | 
  | 
} | 
| 694 | 
  | 
  | 
 | 
| 695 | 
  | 
  | 
/* Shirly-Chiu sample generator */ | 
| 696 | 
  | 
  | 
static int | 
| 697 | 
  | 
  | 
sample_shirchiu(PARAMS *p, int b, FILE *fp) | 
| 698 | 
  | 
  | 
{ | 
| 699 | 
  | 
  | 
        int     n = sampcnt; | 
| 700 | 
  | 
  | 
        double  samp3[3]; | 
| 701 | 
  | 
  | 
        double  duvw[3]; | 
| 702 | 
  | 
  | 
        FVECT   orig_dir[2]; | 
| 703 | 
  | 
  | 
        int     i; | 
| 704 | 
  | 
  | 
 | 
| 705 | 
  | 
  | 
        if (fp == NULL)                 /* just requesting number of bins? */ | 
| 706 | 
  | 
  | 
                return(p->hsiz*p->hsiz); | 
| 707 | 
  | 
  | 
 | 
| 708 | 
  | 
  | 
        while (n--) {                   /* stratified sampling */ | 
| 709 | 
  | 
  | 
                SDmultiSamp(samp3, 3, (n+frandom())/sampcnt); | 
| 710 | 
  | 
  | 
                SDsquare2disk(duvw, (b/p->hsiz + samp3[1])/curparams.hsiz, | 
| 711 | 
  | 
  | 
                                (b%p->hsiz + samp3[2])/curparams.hsiz); | 
| 712 | 
  | 
  | 
                duvw[2] = sqrt(1. - duvw[0]*duvw[0] - duvw[1]*duvw[1]); | 
| 713 | 
  | 
  | 
                for (i = 3; i--; ) | 
| 714 | 
  | 
  | 
                        orig_dir[1][i] = -duvw[0]*p->udir[i] - | 
| 715 | 
  | 
  | 
                                                duvw[1]*p->vdir[i] - | 
| 716 | 
  | 
  | 
                                                duvw[2]*p->nrm[i] ; | 
| 717 | 
  | 
  | 
                if (!sample_origin(p, orig_dir[0], orig_dir[1], samp3[0])) | 
| 718 | 
  | 
  | 
                        return(0); | 
| 719 | 
  | 
  | 
                if (fwrite(orig_dir, sizeof(FVECT), 2, fp) != 2) | 
| 720 | 
  | 
  | 
                        return(0); | 
| 721 | 
  | 
  | 
        } | 
| 722 | 
  | 
  | 
        return(1); | 
| 723 | 
  | 
  | 
} | 
| 724 | 
  | 
  | 
 | 
| 725 | 
  | 
  | 
/* Reinhart/Tregenza sample generator */ | 
| 726 | 
  | 
  | 
static int | 
| 727 | 
  | 
  | 
sample_reinhart(PARAMS *p, int b, FILE *fp) | 
| 728 | 
  | 
  | 
{ | 
| 729 | 
  | 
  | 
#define T_NALT  7 | 
| 730 | 
  | 
  | 
        static const int        tnaz[T_NALT] = {30, 30, 24, 24, 18, 12, 6}; | 
| 731 | 
  | 
  | 
        const int               RowMax = T_NALT*p->hsiz + 1; | 
| 732 | 
greg | 
2.7 | 
        const double            RAH = (.5*PI)/(RowMax-.5); | 
| 733 | 
greg | 
2.1 | 
#define rnaz(r)                 (r >= RowMax-1 ? 1 : p->hsiz*tnaz[r/p->hsiz]) | 
| 734 | 
  | 
  | 
        int                     n = sampcnt; | 
| 735 | 
  | 
  | 
        int                     row, col; | 
| 736 | 
  | 
  | 
        double                  samp3[3]; | 
| 737 | 
  | 
  | 
        double                  alt, azi; | 
| 738 | 
  | 
  | 
        double                  duvw[3]; | 
| 739 | 
  | 
  | 
        FVECT                   orig_dir[2]; | 
| 740 | 
  | 
  | 
        int                     i; | 
| 741 | 
  | 
  | 
 | 
| 742 | 
  | 
  | 
        if (fp == NULL) {               /* just requesting number of bins? */ | 
| 743 | 
  | 
  | 
                n = 0; | 
| 744 | 
  | 
  | 
                for (row = RowMax; row--; ) n += rnaz(row); | 
| 745 | 
  | 
  | 
                return(n); | 
| 746 | 
  | 
  | 
        } | 
| 747 | 
  | 
  | 
        row = 0;                        /* identify row & column */ | 
| 748 | 
  | 
  | 
        col = b; | 
| 749 | 
  | 
  | 
        while (col >= rnaz(row)) { | 
| 750 | 
  | 
  | 
                col -= rnaz(row); | 
| 751 | 
  | 
  | 
                ++row; | 
| 752 | 
  | 
  | 
        } | 
| 753 | 
  | 
  | 
        while (n--) {                   /* stratified sampling */ | 
| 754 | 
  | 
  | 
                SDmultiSamp(samp3, 3, (n+frandom())/sampcnt); | 
| 755 | 
  | 
  | 
                alt = (row+samp3[1])*RAH; | 
| 756 | 
  | 
  | 
                azi = (2.*PI)*(col+samp3[2]-.5)/rnaz(row); | 
| 757 | 
greg | 
2.7 | 
                duvw[2] = cos(alt);     /* measured from horizon */ | 
| 758 | 
greg | 
2.18 | 
                duvw[0] = tsin(azi)*duvw[2]; | 
| 759 | 
  | 
  | 
                duvw[1] = tcos(azi)*duvw[2]; | 
| 760 | 
greg | 
2.1 | 
                duvw[2] = sqrt(1. - duvw[2]*duvw[2]); | 
| 761 | 
  | 
  | 
                for (i = 3; i--; ) | 
| 762 | 
  | 
  | 
                        orig_dir[1][i] = -duvw[0]*p->udir[i] - | 
| 763 | 
  | 
  | 
                                                duvw[1]*p->vdir[i] - | 
| 764 | 
  | 
  | 
                                                duvw[2]*p->nrm[i] ; | 
| 765 | 
  | 
  | 
                if (!sample_origin(p, orig_dir[0], orig_dir[1], samp3[0])) | 
| 766 | 
  | 
  | 
                        return(0); | 
| 767 | 
  | 
  | 
                if (fwrite(orig_dir, sizeof(FVECT), 2, fp) != 2) | 
| 768 | 
  | 
  | 
                        return(0); | 
| 769 | 
  | 
  | 
        } | 
| 770 | 
  | 
  | 
        return(1); | 
| 771 | 
  | 
  | 
#undef rnaz | 
| 772 | 
  | 
  | 
#undef T_NALT | 
| 773 | 
  | 
  | 
} | 
| 774 | 
  | 
  | 
 | 
| 775 | 
  | 
  | 
/* Klems sample generator */ | 
| 776 | 
  | 
  | 
static int | 
| 777 | 
  | 
  | 
sample_klems(PARAMS *p, int b, FILE *fp) | 
| 778 | 
  | 
  | 
{ | 
| 779 | 
  | 
  | 
        static const char       bname[4][20] = { | 
| 780 | 
  | 
  | 
                                        "LBNL/Klems Full", | 
| 781 | 
  | 
  | 
                                        "LBNL/Klems Half", | 
| 782 | 
  | 
  | 
                                        "INTERNAL ERROR", | 
| 783 | 
  | 
  | 
                                        "LBNL/Klems Quarter" | 
| 784 | 
  | 
  | 
                                }; | 
| 785 | 
  | 
  | 
        static ANGLE_BASIS      *kbasis[4]; | 
| 786 | 
  | 
  | 
        const int               bi = p->hemis[1] - '1'; | 
| 787 | 
  | 
  | 
        int                     n = sampcnt; | 
| 788 | 
  | 
  | 
        double                  samp2[2]; | 
| 789 | 
  | 
  | 
        double                  duvw[3]; | 
| 790 | 
  | 
  | 
        FVECT                   orig_dir[2]; | 
| 791 | 
  | 
  | 
        int                     i; | 
| 792 | 
  | 
  | 
 | 
| 793 | 
  | 
  | 
        if (!kbasis[bi]) {              /* need to get basis, first */ | 
| 794 | 
  | 
  | 
                for (i = 4; i--; ) | 
| 795 | 
  | 
  | 
                        if (!strcasecmp(abase_list[i].name, bname[bi])) { | 
| 796 | 
  | 
  | 
                                kbasis[bi] = &abase_list[i]; | 
| 797 | 
  | 
  | 
                                break; | 
| 798 | 
  | 
  | 
                        } | 
| 799 | 
  | 
  | 
                if (i < 0) { | 
| 800 | 
  | 
  | 
                        fprintf(stderr, "%s: unknown hemisphere basis '%s'\n", | 
| 801 | 
  | 
  | 
                                        progname, bname[bi]); | 
| 802 | 
  | 
  | 
                        return(0); | 
| 803 | 
  | 
  | 
                } | 
| 804 | 
  | 
  | 
        } | 
| 805 | 
  | 
  | 
        if (fp == NULL)                 /* just requesting number of bins? */ | 
| 806 | 
  | 
  | 
                return(kbasis[bi]->nangles); | 
| 807 | 
  | 
  | 
 | 
| 808 | 
  | 
  | 
        while (n--) {                   /* stratified sampling */ | 
| 809 | 
  | 
  | 
                SDmultiSamp(samp2, 2, (n+frandom())/sampcnt); | 
| 810 | 
greg | 
2.27 | 
                if (!fo_getvec(duvw, b+samp2[1], kbasis[bi])) | 
| 811 | 
greg | 
2.1 | 
                        return(0); | 
| 812 | 
  | 
  | 
                for (i = 3; i--; ) | 
| 813 | 
greg | 
2.26 | 
                        orig_dir[1][i] = -duvw[0]*p->udir[i] - | 
| 814 | 
  | 
  | 
                                                duvw[1]*p->vdir[i] - | 
| 815 | 
greg | 
2.1 | 
                                                duvw[2]*p->nrm[i] ; | 
| 816 | 
  | 
  | 
                if (!sample_origin(p, orig_dir[0], orig_dir[1], samp2[0])) | 
| 817 | 
  | 
  | 
                        return(0); | 
| 818 | 
  | 
  | 
                if (fwrite(orig_dir, sizeof(FVECT), 2, fp) != 2) | 
| 819 | 
  | 
  | 
                        return(0); | 
| 820 | 
  | 
  | 
        } | 
| 821 | 
  | 
  | 
        return(1); | 
| 822 | 
  | 
  | 
} | 
| 823 | 
  | 
  | 
 | 
| 824 | 
  | 
  | 
/* Prepare hemisphere basis sampler that will send rays to rcontrib */ | 
| 825 | 
  | 
  | 
static int | 
| 826 | 
  | 
  | 
prepare_sampler(void) | 
| 827 | 
  | 
  | 
{ | 
| 828 | 
  | 
  | 
        if (curparams.slist == NULL) {  /* missing sample surface! */ | 
| 829 | 
  | 
  | 
                fputs(progname, stderr); | 
| 830 | 
  | 
  | 
                fputs(": no sender surface!\n", stderr); | 
| 831 | 
  | 
  | 
                return(-1); | 
| 832 | 
  | 
  | 
        } | 
| 833 | 
greg | 
2.16 | 
                                        /* misplaced output file spec. */ | 
| 834 | 
  | 
  | 
        if ((curparams.outfn != NULL) & (verbose >= 0)) | 
| 835 | 
greg | 
2.1 | 
                fprintf(stderr, "%s: warning - ignoring output file in sender ('%s')\n", | 
| 836 | 
  | 
  | 
                                progname, curparams.outfn); | 
| 837 | 
  | 
  | 
                                        /* check/set basis hemisphere */ | 
| 838 | 
  | 
  | 
        if (!curparams.hemis[0]) { | 
| 839 | 
  | 
  | 
                fputs(progname, stderr); | 
| 840 | 
  | 
  | 
                fputs(": missing sender sampling type!\n", stderr); | 
| 841 | 
  | 
  | 
                return(-1); | 
| 842 | 
  | 
  | 
        } | 
| 843 | 
  | 
  | 
        if (normalize(curparams.nrm) == 0) { | 
| 844 | 
  | 
  | 
                fputs(progname, stderr); | 
| 845 | 
  | 
  | 
                fputs(": undefined normal for sender sampling\n", stderr); | 
| 846 | 
  | 
  | 
                return(-1); | 
| 847 | 
  | 
  | 
        } | 
| 848 | 
greg | 
2.10 | 
        if (normalize(curparams.vup) == 0) { | 
| 849 | 
greg | 
2.1 | 
                if (fabs(curparams.nrm[2]) < .7) | 
| 850 | 
  | 
  | 
                        curparams.vup[2] = 1; | 
| 851 | 
  | 
  | 
                else | 
| 852 | 
  | 
  | 
                        curparams.vup[1] = 1; | 
| 853 | 
greg | 
2.10 | 
        } | 
| 854 | 
greg | 
2.26 | 
        fcross(curparams.udir, curparams.vup, curparams.nrm); | 
| 855 | 
greg | 
2.1 | 
        if (normalize(curparams.udir) == 0) { | 
| 856 | 
  | 
  | 
                fputs(progname, stderr); | 
| 857 | 
  | 
  | 
                fputs(": up vector coincides with sender normal\n", stderr); | 
| 858 | 
  | 
  | 
                return(-1); | 
| 859 | 
  | 
  | 
        } | 
| 860 | 
greg | 
2.26 | 
        fcross(curparams.vdir, curparams.nrm, curparams.udir); | 
| 861 | 
  | 
  | 
        if (curparams.sign == '-') {    /* left-handed coordinate system? */ | 
| 862 | 
  | 
  | 
                curparams.udir[0] *= -1.; | 
| 863 | 
  | 
  | 
                curparams.udir[1] *= -1.; | 
| 864 | 
  | 
  | 
                curparams.udir[2] *= -1.; | 
| 865 | 
  | 
  | 
        } | 
| 866 | 
greg | 
2.1 | 
        if (tolower(curparams.hemis[0]) == 'u' | curparams.hemis[0] == '1') | 
| 867 | 
  | 
  | 
                curparams.sample_basis = sample_uniform; | 
| 868 | 
  | 
  | 
        else if (tolower(curparams.hemis[0]) == 's' && | 
| 869 | 
  | 
  | 
                                tolower(curparams.hemis[1]) == 'c') | 
| 870 | 
  | 
  | 
                curparams.sample_basis = sample_shirchiu; | 
| 871 | 
  | 
  | 
        else if ((tolower(curparams.hemis[0]) == 'r') | | 
| 872 | 
  | 
  | 
                        (tolower(curparams.hemis[0]) == 't')) | 
| 873 | 
  | 
  | 
                curparams.sample_basis = sample_reinhart; | 
| 874 | 
  | 
  | 
        else if (tolower(curparams.hemis[0]) == 'k') { | 
| 875 | 
  | 
  | 
                switch (curparams.hemis[1]) { | 
| 876 | 
  | 
  | 
                case '1': | 
| 877 | 
  | 
  | 
                case '2': | 
| 878 | 
  | 
  | 
                case '4': | 
| 879 | 
  | 
  | 
                        break; | 
| 880 | 
  | 
  | 
                case 'f': | 
| 881 | 
  | 
  | 
                case 'F': | 
| 882 | 
  | 
  | 
                case '\0': | 
| 883 | 
  | 
  | 
                        curparams.hemis[1] = '1'; | 
| 884 | 
  | 
  | 
                        break; | 
| 885 | 
  | 
  | 
                case 'h': | 
| 886 | 
  | 
  | 
                case 'H': | 
| 887 | 
  | 
  | 
                        curparams.hemis[1] = '2'; | 
| 888 | 
  | 
  | 
                        break; | 
| 889 | 
  | 
  | 
                case 'q': | 
| 890 | 
  | 
  | 
                case 'Q': | 
| 891 | 
  | 
  | 
                        curparams.hemis[1] = '4'; | 
| 892 | 
  | 
  | 
                        break; | 
| 893 | 
  | 
  | 
                default: | 
| 894 | 
  | 
  | 
                        goto unrecognized; | 
| 895 | 
  | 
  | 
                } | 
| 896 | 
  | 
  | 
                curparams.hemis[2] = '\0'; | 
| 897 | 
  | 
  | 
                curparams.sample_basis = sample_klems; | 
| 898 | 
  | 
  | 
        } else | 
| 899 | 
  | 
  | 
                goto unrecognized; | 
| 900 | 
  | 
  | 
                                        /* return number of bins */ | 
| 901 | 
  | 
  | 
        return((*curparams.sample_basis)(&curparams,0,NULL)); | 
| 902 | 
  | 
  | 
unrecognized: | 
| 903 | 
  | 
  | 
        fprintf(stderr, "%s: unrecognized sender sampling: h=%s\n", | 
| 904 | 
  | 
  | 
                        progname, curparams.hemis); | 
| 905 | 
  | 
  | 
        return(-1); | 
| 906 | 
  | 
  | 
} | 
| 907 | 
  | 
  | 
 | 
| 908 | 
  | 
  | 
/* Compute normal and area for polygon */ | 
| 909 | 
  | 
  | 
static int | 
| 910 | 
  | 
  | 
finish_polygon(SURF *p) | 
| 911 | 
  | 
  | 
{ | 
| 912 | 
  | 
  | 
        const int       nv = p->nfargs / 3; | 
| 913 | 
  | 
  | 
        FVECT           e1, e2, vc; | 
| 914 | 
  | 
  | 
        int             i; | 
| 915 | 
  | 
  | 
 | 
| 916 | 
  | 
  | 
        memset(p->snrm, 0, sizeof(FVECT)); | 
| 917 | 
  | 
  | 
        VSUB(e1, p->farg+3, p->farg); | 
| 918 | 
  | 
  | 
        for (i = 2; i < nv; i++) { | 
| 919 | 
  | 
  | 
                VSUB(e2, p->farg+3*i, p->farg);  | 
| 920 | 
  | 
  | 
                VCROSS(vc, e1, e2); | 
| 921 | 
  | 
  | 
                p->snrm[0] += vc[0]; | 
| 922 | 
  | 
  | 
                p->snrm[1] += vc[1]; | 
| 923 | 
  | 
  | 
                p->snrm[2] += vc[2]; | 
| 924 | 
  | 
  | 
                VCOPY(e1, e2); | 
| 925 | 
  | 
  | 
        } | 
| 926 | 
  | 
  | 
        p->area = normalize(p->snrm)*0.5; | 
| 927 | 
  | 
  | 
        return(p->area > FTINY); | 
| 928 | 
  | 
  | 
} | 
| 929 | 
  | 
  | 
 | 
| 930 | 
  | 
  | 
/* Add a surface to our current parameters */ | 
| 931 | 
  | 
  | 
static void | 
| 932 | 
  | 
  | 
add_surface(int st, const char *oname, FILE *fp) | 
| 933 | 
  | 
  | 
{ | 
| 934 | 
  | 
  | 
        SURF    *snew; | 
| 935 | 
  | 
  | 
        int     n; | 
| 936 | 
  | 
  | 
                                        /* get floating-point arguments */ | 
| 937 | 
  | 
  | 
        if (!fscanf(fp, "%d", &n)) return; | 
| 938 | 
  | 
  | 
        while (n-- > 0) fscanf(fp, "%*s"); | 
| 939 | 
  | 
  | 
        if (!fscanf(fp, "%d", &n)) return; | 
| 940 | 
  | 
  | 
        while (n-- > 0) fscanf(fp, "%*d"); | 
| 941 | 
  | 
  | 
        if (!fscanf(fp, "%d", &n) || n <= 0) return; | 
| 942 | 
  | 
  | 
        snew = (SURF *)malloc(sizeof(SURF) + sizeof(double)*(n-1)); | 
| 943 | 
  | 
  | 
        if (snew == NULL) { | 
| 944 | 
  | 
  | 
                fputs(progname, stderr); | 
| 945 | 
  | 
  | 
                fputs(": out of memory!\n", stderr); | 
| 946 | 
  | 
  | 
                exit(1); | 
| 947 | 
  | 
  | 
        } | 
| 948 | 
  | 
  | 
        strncpy(snew->sname, oname, sizeof(snew->sname)-1); | 
| 949 | 
  | 
  | 
        snew->sname[sizeof(snew->sname)-1] = '\0'; | 
| 950 | 
  | 
  | 
        snew->styp = st; | 
| 951 | 
  | 
  | 
        snew->priv = NULL; | 
| 952 | 
  | 
  | 
        snew->nfargs = n; | 
| 953 | 
  | 
  | 
        for (n = 0; n < snew->nfargs; n++) | 
| 954 | 
  | 
  | 
                if (fscanf(fp, "%lf", &snew->farg[n]) != 1) { | 
| 955 | 
  | 
  | 
                        fprintf(stderr, "%s: error reading arguments for '%s'\n", | 
| 956 | 
  | 
  | 
                                        progname, oname); | 
| 957 | 
  | 
  | 
                        exit(1); | 
| 958 | 
  | 
  | 
                } | 
| 959 | 
  | 
  | 
        switch (st) { | 
| 960 | 
  | 
  | 
        case ST_RING: | 
| 961 | 
  | 
  | 
                if (snew->nfargs != 8) | 
| 962 | 
  | 
  | 
                        goto badcount; | 
| 963 | 
  | 
  | 
                VCOPY(snew->snrm, snew->farg+3); | 
| 964 | 
  | 
  | 
                if (normalize(snew->snrm) == 0) | 
| 965 | 
  | 
  | 
                        goto badnorm; | 
| 966 | 
  | 
  | 
                if (snew->farg[7] < snew->farg[6]) { | 
| 967 | 
  | 
  | 
                        double  t = snew->farg[7]; | 
| 968 | 
  | 
  | 
                        snew->farg[7] = snew->farg[6]; | 
| 969 | 
  | 
  | 
                        snew->farg[6] = t; | 
| 970 | 
  | 
  | 
                } | 
| 971 | 
  | 
  | 
                snew->area = PI*(snew->farg[7]*snew->farg[7] - | 
| 972 | 
  | 
  | 
                                        snew->farg[6]*snew->farg[6]); | 
| 973 | 
  | 
  | 
                break; | 
| 974 | 
  | 
  | 
        case ST_POLY: | 
| 975 | 
  | 
  | 
                if (snew->nfargs < 9 || snew->nfargs % 3) | 
| 976 | 
  | 
  | 
                        goto badcount; | 
| 977 | 
  | 
  | 
                finish_polygon(snew); | 
| 978 | 
  | 
  | 
                break; | 
| 979 | 
  | 
  | 
        case ST_SOURCE: | 
| 980 | 
  | 
  | 
                if (snew->nfargs != 4) | 
| 981 | 
  | 
  | 
                        goto badcount; | 
| 982 | 
greg | 
2.8 | 
                for (n = 3; n--; )      /* need to reverse "normal" */ | 
| 983 | 
  | 
  | 
                        snew->snrm[n] = -snew->farg[n]; | 
| 984 | 
greg | 
2.1 | 
                if (normalize(snew->snrm) == 0) | 
| 985 | 
  | 
  | 
                        goto badnorm; | 
| 986 | 
greg | 
2.4 | 
                snew->area = sin((PI/180./2.)*snew->farg[3]); | 
| 987 | 
  | 
  | 
                snew->area *= PI*snew->area; | 
| 988 | 
greg | 
2.1 | 
                break; | 
| 989 | 
  | 
  | 
        } | 
| 990 | 
greg | 
2.16 | 
        if ((snew->area <= FTINY) & (verbose >= 0)) { | 
| 991 | 
greg | 
2.1 | 
                fprintf(stderr, "%s: warning - zero area for surface '%s'\n", | 
| 992 | 
  | 
  | 
                                progname, oname); | 
| 993 | 
  | 
  | 
                free(snew); | 
| 994 | 
  | 
  | 
                return; | 
| 995 | 
  | 
  | 
        } | 
| 996 | 
  | 
  | 
        VSUM(curparams.nrm, curparams.nrm, snew->snrm, snew->area); | 
| 997 | 
  | 
  | 
        snew->next = curparams.slist; | 
| 998 | 
  | 
  | 
        curparams.slist = snew; | 
| 999 | 
  | 
  | 
        curparams.nsurfs++; | 
| 1000 | 
  | 
  | 
        return; | 
| 1001 | 
  | 
  | 
badcount: | 
| 1002 | 
greg | 
2.7 | 
        fprintf(stderr, "%s: bad argument count for surface element '%s'\n", | 
| 1003 | 
greg | 
2.1 | 
                        progname, oname); | 
| 1004 | 
  | 
  | 
        exit(1); | 
| 1005 | 
  | 
  | 
badnorm: | 
| 1006 | 
greg | 
2.7 | 
        fprintf(stderr, "%s: bad orientation for surface element '%s'\n", | 
| 1007 | 
greg | 
2.1 | 
                        progname, oname); | 
| 1008 | 
  | 
  | 
        exit(1); | 
| 1009 | 
  | 
  | 
} | 
| 1010 | 
  | 
  | 
 | 
| 1011 | 
  | 
  | 
/* Parse a receiver object (look for modifiers to add to rcontrib command) */ | 
| 1012 | 
  | 
  | 
static int | 
| 1013 | 
  | 
  | 
add_recv_object(FILE *fp) | 
| 1014 | 
  | 
  | 
{ | 
| 1015 | 
  | 
  | 
        int             st; | 
| 1016 | 
  | 
  | 
        char            thismod[128], otype[32], oname[128]; | 
| 1017 | 
  | 
  | 
        int             n; | 
| 1018 | 
  | 
  | 
 | 
| 1019 | 
  | 
  | 
        if (fscanf(fp, "%s %s %s", thismod, otype, oname) != 3) | 
| 1020 | 
  | 
  | 
                return(0);              /* must have hit EOF! */ | 
| 1021 | 
  | 
  | 
        if (!strcmp(otype, "alias")) { | 
| 1022 | 
  | 
  | 
                fscanf(fp, "%*s");      /* skip alias */ | 
| 1023 | 
  | 
  | 
                return(0); | 
| 1024 | 
  | 
  | 
        } | 
| 1025 | 
  | 
  | 
                                        /* is it a new receiver? */ | 
| 1026 | 
  | 
  | 
        if ((st = surf_type(otype)) != ST_NONE) { | 
| 1027 | 
  | 
  | 
                if (curparams.slist != NULL && (st == ST_SOURCE) ^ | 
| 1028 | 
  | 
  | 
                                (curparams.slist->styp == ST_SOURCE)) { | 
| 1029 | 
  | 
  | 
                        fputs(progname, stderr); | 
| 1030 | 
  | 
  | 
                        fputs(": cannot mix source/non-source receivers!\n", stderr); | 
| 1031 | 
  | 
  | 
                        return(-1); | 
| 1032 | 
  | 
  | 
                } | 
| 1033 | 
  | 
  | 
                if (strcmp(thismod, curmod)) { | 
| 1034 | 
  | 
  | 
                        if (curmod[0]) {        /* output last receiver? */ | 
| 1035 | 
  | 
  | 
                                finish_receiver(); | 
| 1036 | 
  | 
  | 
                                clear_params(&curparams, 1); | 
| 1037 | 
  | 
  | 
                        } | 
| 1038 | 
greg | 
2.6 | 
                        parse_params(&curparams, newparams); | 
| 1039 | 
  | 
  | 
                        newparams[0] = '\0'; | 
| 1040 | 
greg | 
2.1 | 
                        strcpy(curmod, thismod); | 
| 1041 | 
  | 
  | 
                } | 
| 1042 | 
  | 
  | 
                add_surface(st, oname, fp);     /* read & store surface */ | 
| 1043 | 
  | 
  | 
                return(1); | 
| 1044 | 
  | 
  | 
        } | 
| 1045 | 
  | 
  | 
                                        /* else skip arguments */ | 
| 1046 | 
greg | 
2.8 | 
        if (!fscanf(fp, "%d", &n)) return(0); | 
| 1047 | 
greg | 
2.1 | 
        while (n-- > 0) fscanf(fp, "%*s"); | 
| 1048 | 
greg | 
2.10 | 
        if (!fscanf(fp, "%d", &n)) return(0); | 
| 1049 | 
greg | 
2.1 | 
        while (n-- > 0) fscanf(fp, "%*d"); | 
| 1050 | 
greg | 
2.10 | 
        if (!fscanf(fp, "%d", &n)) return(0); | 
| 1051 | 
greg | 
2.1 | 
        while (n-- > 0) fscanf(fp, "%*f"); | 
| 1052 | 
  | 
  | 
        return(0); | 
| 1053 | 
  | 
  | 
} | 
| 1054 | 
  | 
  | 
 | 
| 1055 | 
  | 
  | 
/* Parse a sender object */ | 
| 1056 | 
  | 
  | 
static int | 
| 1057 | 
  | 
  | 
add_send_object(FILE *fp) | 
| 1058 | 
  | 
  | 
{ | 
| 1059 | 
  | 
  | 
        int             st; | 
| 1060 | 
greg | 
2.24 | 
        char            thismod[128], otype[32], oname[128]; | 
| 1061 | 
greg | 
2.1 | 
        int             n; | 
| 1062 | 
  | 
  | 
 | 
| 1063 | 
greg | 
2.25 | 
        if (fscanf(fp, "%s %s %s", thismod, otype, oname) != 3) | 
| 1064 | 
greg | 
2.1 | 
                return(0);              /* must have hit EOF! */ | 
| 1065 | 
  | 
  | 
        if (!strcmp(otype, "alias")) { | 
| 1066 | 
  | 
  | 
                fscanf(fp, "%*s");      /* skip alias */ | 
| 1067 | 
  | 
  | 
                return(0); | 
| 1068 | 
  | 
  | 
        } | 
| 1069 | 
  | 
  | 
                                        /* is it a new surface? */ | 
| 1070 | 
  | 
  | 
        if ((st = surf_type(otype)) != ST_NONE) { | 
| 1071 | 
  | 
  | 
                if (st == ST_SOURCE) { | 
| 1072 | 
  | 
  | 
                        fputs(progname, stderr); | 
| 1073 | 
  | 
  | 
                        fputs(": cannot use source as a sender!\n", stderr); | 
| 1074 | 
  | 
  | 
                        return(-1); | 
| 1075 | 
  | 
  | 
                } | 
| 1076 | 
greg | 
2.24 | 
                if (strcmp(thismod, curmod)) { | 
| 1077 | 
  | 
  | 
                        if (curmod[0]) { | 
| 1078 | 
  | 
  | 
                                fputs(progname, stderr); | 
| 1079 | 
  | 
  | 
                                fputs(": warning - multiple modifiers in sender\n", | 
| 1080 | 
  | 
  | 
                                                stderr); | 
| 1081 | 
  | 
  | 
                        } | 
| 1082 | 
  | 
  | 
                        strcpy(curmod, thismod); | 
| 1083 | 
  | 
  | 
                } | 
| 1084 | 
greg | 
2.6 | 
                parse_params(&curparams, newparams); | 
| 1085 | 
  | 
  | 
                newparams[0] = '\0'; | 
| 1086 | 
greg | 
2.1 | 
                add_surface(st, oname, fp);     /* read & store surface */ | 
| 1087 | 
  | 
  | 
                return(0); | 
| 1088 | 
  | 
  | 
        } | 
| 1089 | 
  | 
  | 
                                        /* else skip arguments */ | 
| 1090 | 
greg | 
2.8 | 
        if (!fscanf(fp, "%d", &n)) return(0); | 
| 1091 | 
greg | 
2.1 | 
        while (n-- > 0) fscanf(fp, "%*s"); | 
| 1092 | 
greg | 
2.10 | 
        if (!fscanf(fp, "%d", &n)) return(0); | 
| 1093 | 
greg | 
2.1 | 
        while (n-- > 0) fscanf(fp, "%*d"); | 
| 1094 | 
greg | 
2.10 | 
        if (!fscanf(fp, "%d", &n)) return(0); | 
| 1095 | 
greg | 
2.1 | 
        while (n-- > 0) fscanf(fp, "%*f"); | 
| 1096 | 
  | 
  | 
        return(0); | 
| 1097 | 
  | 
  | 
} | 
| 1098 | 
  | 
  | 
 | 
| 1099 | 
  | 
  | 
/* Load a Radiance scene using the given callback function for objects */ | 
| 1100 | 
  | 
  | 
static int | 
| 1101 | 
  | 
  | 
load_scene(const char *inspec, int (*ocb)(FILE *)) | 
| 1102 | 
  | 
  | 
{ | 
| 1103 | 
  | 
  | 
        int     rv = 0; | 
| 1104 | 
  | 
  | 
        char    inpbuf[1024]; | 
| 1105 | 
  | 
  | 
        FILE    *fp; | 
| 1106 | 
  | 
  | 
        int     c; | 
| 1107 | 
  | 
  | 
 | 
| 1108 | 
  | 
  | 
        if (*inspec == '!') | 
| 1109 | 
  | 
  | 
                fp = popen(inspec+1, "r"); | 
| 1110 | 
  | 
  | 
        else | 
| 1111 | 
  | 
  | 
                fp = fopen(inspec, "r"); | 
| 1112 | 
  | 
  | 
        if (fp == NULL) { | 
| 1113 | 
  | 
  | 
                fprintf(stderr, "%s: cannot load '%s'\n", progname, inspec); | 
| 1114 | 
  | 
  | 
                return(-1); | 
| 1115 | 
  | 
  | 
        } | 
| 1116 | 
  | 
  | 
        while ((c = getc(fp)) != EOF) { /* load receiver data */ | 
| 1117 | 
  | 
  | 
                if (isspace(c))         /* skip leading white space */ | 
| 1118 | 
  | 
  | 
                        continue; | 
| 1119 | 
  | 
  | 
                if (c == '!') {         /* read from a new command */ | 
| 1120 | 
  | 
  | 
                        inpbuf[0] = c; | 
| 1121 | 
  | 
  | 
                        if (fgetline(inpbuf+1, sizeof(inpbuf)-1, fp) != NULL) { | 
| 1122 | 
  | 
  | 
                                if ((c = load_scene(inpbuf, ocb)) < 0) | 
| 1123 | 
  | 
  | 
                                        return(c); | 
| 1124 | 
  | 
  | 
                                rv += c; | 
| 1125 | 
  | 
  | 
                        } | 
| 1126 | 
  | 
  | 
                        continue; | 
| 1127 | 
  | 
  | 
                } | 
| 1128 | 
  | 
  | 
                if (c == '#') {         /* parameters/comment */ | 
| 1129 | 
greg | 
2.5 | 
                        if ((c = getc(fp)) == EOF || ungetc(c,fp) == EOF) | 
| 1130 | 
  | 
  | 
                                break; | 
| 1131 | 
  | 
  | 
                        if (!isspace(c) && fscanf(fp, "%s", inpbuf) == 1 && | 
| 1132 | 
greg | 
2.1 | 
                                        !strcmp(inpbuf, PARAMSTART)) { | 
| 1133 | 
  | 
  | 
                                if (fgets(inpbuf, sizeof(inpbuf), fp) != NULL) | 
| 1134 | 
greg | 
2.6 | 
                                        strcat(newparams, inpbuf); | 
| 1135 | 
greg | 
2.1 | 
                                continue; | 
| 1136 | 
  | 
  | 
                        } | 
| 1137 | 
greg | 
2.10 | 
                        while ((c = getc(fp)) != EOF && c != '\n') | 
| 1138 | 
greg | 
2.1 | 
                                ;       /* else skipping comment */ | 
| 1139 | 
  | 
  | 
                        continue; | 
| 1140 | 
  | 
  | 
                } | 
| 1141 | 
  | 
  | 
                ungetc(c, fp);          /* else check object for receiver */ | 
| 1142 | 
  | 
  | 
                c = (*ocb)(fp); | 
| 1143 | 
  | 
  | 
                if (c < 0) | 
| 1144 | 
  | 
  | 
                        return(c); | 
| 1145 | 
  | 
  | 
                rv += c; | 
| 1146 | 
  | 
  | 
        } | 
| 1147 | 
  | 
  | 
                                        /* close our input stream */ | 
| 1148 | 
  | 
  | 
        c = (*inspec == '!') ? pclose(fp) : fclose(fp); | 
| 1149 | 
  | 
  | 
        if (c != 0) { | 
| 1150 | 
  | 
  | 
                fprintf(stderr, "%s: error loading '%s'\n", progname, inspec); | 
| 1151 | 
  | 
  | 
                return(-1); | 
| 1152 | 
  | 
  | 
        } | 
| 1153 | 
  | 
  | 
        return(rv); | 
| 1154 | 
  | 
  | 
} | 
| 1155 | 
  | 
  | 
 | 
| 1156 | 
  | 
  | 
/* Get command arguments and run program */ | 
| 1157 | 
  | 
  | 
int | 
| 1158 | 
  | 
  | 
main(int argc, char *argv[]) | 
| 1159 | 
  | 
  | 
{ | 
| 1160 | 
  | 
  | 
        char    fmtopt[6] = "-faa";     /* default output is ASCII */ | 
| 1161 | 
greg | 
2.4 | 
        char    *xrs=NULL, *yrs=NULL, *ldopt=NULL; | 
| 1162 | 
greg | 
2.11 | 
        char    *iropt = NULL; | 
| 1163 | 
greg | 
2.1 | 
        char    *sendfn; | 
| 1164 | 
  | 
  | 
        char    sampcntbuf[32], nsbinbuf[32]; | 
| 1165 | 
  | 
  | 
        FILE    *rcfp; | 
| 1166 | 
  | 
  | 
        int     nsbins; | 
| 1167 | 
  | 
  | 
        int     a, i; | 
| 1168 | 
  | 
  | 
                                        /* screen rcontrib options */ | 
| 1169 | 
  | 
  | 
        progname = argv[0]; | 
| 1170 | 
greg | 
2.14 | 
        for (a = 1; a < argc-2; a++) { | 
| 1171 | 
  | 
  | 
                int     na; | 
| 1172 | 
  | 
  | 
                                        /* check for argument expansion */ | 
| 1173 | 
  | 
  | 
                while ((na = expandarg(&argc, &argv, a)) > 0) | 
| 1174 | 
  | 
  | 
                        ; | 
| 1175 | 
  | 
  | 
                if (na < 0) { | 
| 1176 | 
  | 
  | 
                        fprintf(stderr, "%s: cannot expand '%s'\n", | 
| 1177 | 
  | 
  | 
                                        progname, argv[a]); | 
| 1178 | 
  | 
  | 
                        return(1); | 
| 1179 | 
  | 
  | 
                } | 
| 1180 | 
  | 
  | 
                if (argv[a][0] != '-' || !argv[a][1]) | 
| 1181 | 
  | 
  | 
                        break; | 
| 1182 | 
  | 
  | 
                na = 1;  | 
| 1183 | 
  | 
  | 
                switch (argv[a][1]) {   /* !! Keep consistent !! */ | 
| 1184 | 
greg | 
2.1 | 
                case 'v':               /* verbose mode */ | 
| 1185 | 
greg | 
2.16 | 
                        verbose = 1; | 
| 1186 | 
greg | 
2.1 | 
                        na = 0; | 
| 1187 | 
  | 
  | 
                        continue; | 
| 1188 | 
  | 
  | 
                case 'f':               /* special case for -fo, -ff, etc. */ | 
| 1189 | 
  | 
  | 
                        switch (argv[a][2]) { | 
| 1190 | 
  | 
  | 
                        case '\0':              /* cal file */ | 
| 1191 | 
  | 
  | 
                                goto userr; | 
| 1192 | 
  | 
  | 
                        case 'o':               /* force output */ | 
| 1193 | 
  | 
  | 
                                goto userr; | 
| 1194 | 
  | 
  | 
                        case 'a':               /* output format */ | 
| 1195 | 
  | 
  | 
                        case 'f': | 
| 1196 | 
  | 
  | 
                        case 'd': | 
| 1197 | 
  | 
  | 
                        case 'c': | 
| 1198 | 
greg | 
2.6 | 
                                if (!(fmtopt[3] = argv[a][3])) | 
| 1199 | 
  | 
  | 
                                        fmtopt[3] = argv[a][2]; | 
| 1200 | 
  | 
  | 
                                fmtopt[2] = argv[a][2]; | 
| 1201 | 
greg | 
2.1 | 
                                na = 0; | 
| 1202 | 
  | 
  | 
                                continue;       /* will pass later */ | 
| 1203 | 
  | 
  | 
                        default: | 
| 1204 | 
  | 
  | 
                                goto userr; | 
| 1205 | 
  | 
  | 
                        } | 
| 1206 | 
  | 
  | 
                        break; | 
| 1207 | 
greg | 
2.4 | 
                case 'x':               /* x-resolution */ | 
| 1208 | 
  | 
  | 
                        xrs = argv[++a]; | 
| 1209 | 
  | 
  | 
                        na = 0; | 
| 1210 | 
  | 
  | 
                        continue; | 
| 1211 | 
  | 
  | 
                case 'y':               /* y-resolution */ | 
| 1212 | 
  | 
  | 
                        yrs = argv[++a]; | 
| 1213 | 
  | 
  | 
                        na = 0; | 
| 1214 | 
  | 
  | 
                        continue; | 
| 1215 | 
greg | 
2.1 | 
                case 'c':               /* number of samples */ | 
| 1216 | 
greg | 
2.6 | 
                        sampcnt = atoi(argv[++a]); | 
| 1217 | 
greg | 
2.1 | 
                        if (sampcnt <= 0) | 
| 1218 | 
  | 
  | 
                                goto userr; | 
| 1219 | 
  | 
  | 
                        na = 0;         /* we re-add this later */ | 
| 1220 | 
  | 
  | 
                        continue; | 
| 1221 | 
greg | 
2.8 | 
                case 'I':               /* only for pass-through mode */ | 
| 1222 | 
greg | 
2.11 | 
                case 'i': | 
| 1223 | 
  | 
  | 
                        iropt = argv[a]; | 
| 1224 | 
greg | 
2.8 | 
                        na = 0; | 
| 1225 | 
  | 
  | 
                        continue; | 
| 1226 | 
greg | 
2.16 | 
                case 'w':               /* options without arguments */ | 
| 1227 | 
  | 
  | 
                        if (argv[a][2] != '+') verbose = -1; | 
| 1228 | 
  | 
  | 
                case 'V': | 
| 1229 | 
greg | 
2.1 | 
                case 'u': | 
| 1230 | 
  | 
  | 
                case 'h': | 
| 1231 | 
greg | 
2.4 | 
                case 'r': | 
| 1232 | 
greg | 
2.1 | 
                        break; | 
| 1233 | 
  | 
  | 
                case 'n':               /* options with 1 argument */ | 
| 1234 | 
  | 
  | 
                case 's': | 
| 1235 | 
  | 
  | 
                case 'o': | 
| 1236 | 
  | 
  | 
                        na = 2; | 
| 1237 | 
  | 
  | 
                        break; | 
| 1238 | 
  | 
  | 
                case 'b':               /* special case */ | 
| 1239 | 
  | 
  | 
                        if (argv[a][2] != 'v') goto userr; | 
| 1240 | 
  | 
  | 
                        break; | 
| 1241 | 
  | 
  | 
                case 'l':               /* special case */ | 
| 1242 | 
greg | 
2.4 | 
                        if (argv[a][2] == 'd') { | 
| 1243 | 
  | 
  | 
                                ldopt = argv[a]; | 
| 1244 | 
  | 
  | 
                                na = 0; | 
| 1245 | 
  | 
  | 
                                continue; | 
| 1246 | 
  | 
  | 
                        } | 
| 1247 | 
greg | 
2.1 | 
                        na = 2; | 
| 1248 | 
  | 
  | 
                        break; | 
| 1249 | 
  | 
  | 
                case 'd':               /* special case */ | 
| 1250 | 
  | 
  | 
                        if (argv[a][2] != 'v') na = 2; | 
| 1251 | 
  | 
  | 
                        break; | 
| 1252 | 
  | 
  | 
                case 'a':               /* special case */ | 
| 1253 | 
greg | 
2.28 | 
                        if (argv[a][2] == 'p') { | 
| 1254 | 
  | 
  | 
                                na = 2; /* photon map [+ bandwidth(s)] */ | 
| 1255 | 
  | 
  | 
                                if (a < argc-3 && atoi(argv[a+1]) > 0) | 
| 1256 | 
  | 
  | 
                                        na += 1 + (a < argc-4 && atoi(argv[a+2]) > 0); | 
| 1257 | 
  | 
  | 
                        } else | 
| 1258 | 
  | 
  | 
                                na = (argv[a][2] == 'v') ? 4 : 2; | 
| 1259 | 
greg | 
2.1 | 
                        break; | 
| 1260 | 
  | 
  | 
                case 'm':               /* special case */ | 
| 1261 | 
  | 
  | 
                        if (!argv[a][2]) goto userr; | 
| 1262 | 
  | 
  | 
                        na = (argv[a][2] == 'e') | (argv[a][2] == 'a') ? 4 : 2; | 
| 1263 | 
  | 
  | 
                        break; | 
| 1264 | 
  | 
  | 
                default:                /* anything else is verbotten */ | 
| 1265 | 
  | 
  | 
                        goto userr; | 
| 1266 | 
  | 
  | 
                } | 
| 1267 | 
  | 
  | 
                if (na <= 0) continue; | 
| 1268 | 
  | 
  | 
                CHECKARGC(na);          /* pass on option */ | 
| 1269 | 
  | 
  | 
                rcarg[nrcargs++] = argv[a]; | 
| 1270 | 
  | 
  | 
                while (--na)            /* + arguments if any */ | 
| 1271 | 
  | 
  | 
                        rcarg[nrcargs++] = argv[++a]; | 
| 1272 | 
  | 
  | 
        } | 
| 1273 | 
  | 
  | 
        if (a > argc-2) | 
| 1274 | 
  | 
  | 
                goto userr;             /* check at end of options */ | 
| 1275 | 
  | 
  | 
        sendfn = argv[a++];             /* assign sender & receiver inputs */ | 
| 1276 | 
  | 
  | 
        if (sendfn[0] == '-') {         /* user wants pass-through mode? */ | 
| 1277 | 
  | 
  | 
                if (sendfn[1]) goto userr; | 
| 1278 | 
  | 
  | 
                sendfn = NULL; | 
| 1279 | 
greg | 
2.11 | 
                if (iropt) { | 
| 1280 | 
greg | 
2.8 | 
                        CHECKARGC(1); | 
| 1281 | 
greg | 
2.11 | 
                        rcarg[nrcargs++] = iropt; | 
| 1282 | 
greg | 
2.8 | 
                } | 
| 1283 | 
greg | 
2.4 | 
                if (xrs) { | 
| 1284 | 
  | 
  | 
                        CHECKARGC(2); | 
| 1285 | 
  | 
  | 
                        rcarg[nrcargs++] = "-x"; | 
| 1286 | 
  | 
  | 
                        rcarg[nrcargs++] = xrs; | 
| 1287 | 
  | 
  | 
                } | 
| 1288 | 
  | 
  | 
                if (yrs) { | 
| 1289 | 
  | 
  | 
                        CHECKARGC(2); | 
| 1290 | 
  | 
  | 
                        rcarg[nrcargs++] = "-y"; | 
| 1291 | 
  | 
  | 
                        rcarg[nrcargs++] = yrs; | 
| 1292 | 
  | 
  | 
                } | 
| 1293 | 
  | 
  | 
                if (ldopt) { | 
| 1294 | 
  | 
  | 
                        CHECKARGC(1); | 
| 1295 | 
  | 
  | 
                        rcarg[nrcargs++] = ldopt; | 
| 1296 | 
  | 
  | 
                } | 
| 1297 | 
greg | 
2.1 | 
                if (sampcnt <= 0) sampcnt = 1; | 
| 1298 | 
greg | 
2.8 | 
        } else {                        /* else in sampling mode */ | 
| 1299 | 
greg | 
2.11 | 
                if (iropt) { | 
| 1300 | 
greg | 
2.8 | 
                        fputs(progname, stderr); | 
| 1301 | 
greg | 
2.11 | 
                        fputs(": -i, -I supported for pass-through only\n", stderr); | 
| 1302 | 
greg | 
2.8 | 
                        return(1); | 
| 1303 | 
  | 
  | 
                } | 
| 1304 | 
greg | 
2.6 | 
                fmtopt[2] = (sizeof(RREAL)==sizeof(double)) ? 'd' : 'f'; | 
| 1305 | 
greg | 
2.1 | 
                if (sampcnt <= 0) sampcnt = 10000; | 
| 1306 | 
  | 
  | 
        } | 
| 1307 | 
  | 
  | 
        sprintf(sampcntbuf, "%d", sampcnt); | 
| 1308 | 
  | 
  | 
        CHECKARGC(3);                   /* add our format & sample count */ | 
| 1309 | 
  | 
  | 
        rcarg[nrcargs++] = fmtopt; | 
| 1310 | 
  | 
  | 
        rcarg[nrcargs++] = "-c"; | 
| 1311 | 
  | 
  | 
        rcarg[nrcargs++] = sampcntbuf; | 
| 1312 | 
  | 
  | 
                                        /* add receiver arguments to rcontrib */ | 
| 1313 | 
  | 
  | 
        if (load_scene(argv[a], add_recv_object) < 0) | 
| 1314 | 
  | 
  | 
                return(1); | 
| 1315 | 
  | 
  | 
        finish_receiver(); | 
| 1316 | 
  | 
  | 
        if (sendfn == NULL) {           /* pass-through mode? */ | 
| 1317 | 
  | 
  | 
                CHECKARGC(1);           /* add octree */ | 
| 1318 | 
  | 
  | 
                rcarg[nrcargs++] = oconv_command(argc-a, argv+a); | 
| 1319 | 
  | 
  | 
                rcarg[nrcargs] = NULL; | 
| 1320 | 
  | 
  | 
                return(my_exec(rcarg)); /* rcontrib does everything */ | 
| 1321 | 
  | 
  | 
        } | 
| 1322 | 
  | 
  | 
        clear_params(&curparams, 0);    /* else load sender surface & params */ | 
| 1323 | 
greg | 
2.24 | 
        curmod[0] = '\0'; | 
| 1324 | 
greg | 
2.1 | 
        if (load_scene(sendfn, add_send_object) < 0) | 
| 1325 | 
  | 
  | 
                return(1); | 
| 1326 | 
  | 
  | 
        if ((nsbins = prepare_sampler()) <= 0) | 
| 1327 | 
  | 
  | 
                return(1); | 
| 1328 | 
  | 
  | 
        CHECKARGC(3);                   /* add row count and octree */ | 
| 1329 | 
  | 
  | 
        rcarg[nrcargs++] = "-y"; | 
| 1330 | 
  | 
  | 
        sprintf(nsbinbuf, "%d", nsbins); | 
| 1331 | 
  | 
  | 
        rcarg[nrcargs++] = nsbinbuf; | 
| 1332 | 
  | 
  | 
        rcarg[nrcargs++] = oconv_command(argc-a, argv+a); | 
| 1333 | 
  | 
  | 
        rcarg[nrcargs] = NULL; | 
| 1334 | 
  | 
  | 
                                        /* open pipe to rcontrib process */ | 
| 1335 | 
  | 
  | 
        if ((rcfp = popen_arglist(rcarg, "w")) == NULL) | 
| 1336 | 
  | 
  | 
                return(1); | 
| 1337 | 
  | 
  | 
        SET_FILE_BINARY(rcfp); | 
| 1338 | 
  | 
  | 
#ifdef getc_unlocked | 
| 1339 | 
  | 
  | 
        flockfile(rcfp); | 
| 1340 | 
  | 
  | 
#endif | 
| 1341 | 
greg | 
2.22 | 
        if (verbose > 0) { | 
| 1342 | 
greg | 
2.1 | 
                fprintf(stderr, "%s: sampling %d directions", progname, nsbins); | 
| 1343 | 
  | 
  | 
                if (curparams.nsurfs > 1) | 
| 1344 | 
greg | 
2.7 | 
                        fprintf(stderr, " (%d elements)\n", curparams.nsurfs); | 
| 1345 | 
greg | 
2.1 | 
                else | 
| 1346 | 
  | 
  | 
                        fputc('\n', stderr); | 
| 1347 | 
  | 
  | 
        } | 
| 1348 | 
  | 
  | 
        for (i = 0; i < nsbins; i++)    /* send rcontrib ray samples */ | 
| 1349 | 
  | 
  | 
                if (!(*curparams.sample_basis)(&curparams, i, rcfp)) | 
| 1350 | 
  | 
  | 
                        return(1); | 
| 1351 | 
greg | 
2.23 | 
        return(pclose(rcfp) < 0);       /* all finished! */ | 
| 1352 | 
greg | 
2.1 | 
userr: | 
| 1353 | 
  | 
  | 
        if (a < argc-2) | 
| 1354 | 
  | 
  | 
                fprintf(stderr, "%s: unsupported option '%s'", progname, argv[a]); | 
| 1355 | 
greg | 
2.13 | 
        fprintf(stderr, "Usage: %s [-v][rcontrib options] sender.rad receiver.rad [-i system.oct] [system.rad ..]\n", | 
| 1356 | 
greg | 
2.1 | 
                                progname); | 
| 1357 | 
  | 
  | 
        return(1); | 
| 1358 | 
  | 
  | 
} |