| 1 | gwlarson | 3.1 | /* Copyright (c) 1998 Silicon Graphics, Inc. */ | 
| 2 |  |  |  | 
| 3 |  |  | #ifndef lint | 
| 4 |  |  | static char SCCSid[] = "$SunId$ SGI"; | 
| 5 |  |  | #endif | 
| 6 |  |  |  | 
| 7 |  |  | /* | 
| 8 | gwlarson | 3.5 | * Routines for loading and displaying Radiance objects in rholo with GLX. | 
| 9 | gwlarson | 3.1 | */ | 
| 10 |  |  |  | 
| 11 |  |  | #include "radogl.h" | 
| 12 |  |  | #include "tonemap.h" | 
| 13 |  |  | #include "rhdisp.h" | 
| 14 |  |  | #include "rhdriver.h" | 
| 15 |  |  | #include "rhdobj.h" | 
| 16 |  |  |  | 
| 17 |  |  | extern FILE     *sstdout;               /* user standard output */ | 
| 18 |  |  |  | 
| 19 |  |  | char    rhdcmd[DO_NCMDS][8] = DO_INIT;  /* user command list */ | 
| 20 |  |  |  | 
| 21 |  |  | int     (*dobj_lightsamp)() = NULL;     /* pointer to function to get lights */ | 
| 22 |  |  |  | 
| 23 |  |  | #define AVGREFL         0.5             /* assumed average reflectance */ | 
| 24 |  |  |  | 
| 25 | gwlarson | 3.6 | #define MAXAC           512             /* maximum number of args */ | 
| 26 | gwlarson | 3.1 |  | 
| 27 |  |  | #ifndef MINTHRESH | 
| 28 | gwlarson | 3.2 | #define MINTHRESH       5.0             /* source threshold w.r.t. mean */ | 
| 29 | gwlarson | 3.1 | #endif | 
| 30 |  |  |  | 
| 31 |  |  | #ifndef NALT | 
| 32 |  |  | #define NALT            11              /* # sampling altitude angles */ | 
| 33 |  |  | #endif | 
| 34 |  |  | #ifndef NAZI | 
| 35 |  |  | #define NAZI            ((int)(PI/2.*NALT+.5)) | 
| 36 |  |  | #endif | 
| 37 |  |  |  | 
| 38 |  |  | typedef struct dlights { | 
| 39 |  |  | struct dlights  *next;          /* next in lighting set list */ | 
| 40 |  |  | FVECT   lcent;                  /* computed lighting center */ | 
| 41 |  |  | double  ravg;                   /* harmonic mean free range radius */ | 
| 42 |  |  | TMbright        larb;           /* average reflected brightness */ | 
| 43 |  |  | COLOR   lamb;                   /* local ambient value */ | 
| 44 |  |  | short   nl;                     /* number of lights in this set */ | 
| 45 |  |  | struct lsource { | 
| 46 |  |  | FVECT   direc;                  /* source direction */ | 
| 47 |  |  | double  omega;                  /* source solid angle */ | 
| 48 |  |  | COLOR   val;                    /* source color */ | 
| 49 |  |  | } li[MAXLIGHTS];                /* light sources */ | 
| 50 |  |  | } DLIGHTS;                      /* a light source set */ | 
| 51 |  |  |  | 
| 52 |  |  | typedef struct dobject { | 
| 53 |  |  | struct dobject  *next;          /* next object in list */ | 
| 54 |  |  | char    name[64];               /* object name */ | 
| 55 |  |  | FVECT   center;                 /* orig. object center */ | 
| 56 |  |  | FLOAT   radius;                 /* orig. object radius */ | 
| 57 |  |  | int     listid;                 /* GL display list identifier */ | 
| 58 |  |  | int     rtp[3];                 /* associated rtrace process */ | 
| 59 |  |  | DLIGHTS *ol;                    /* object lights */ | 
| 60 |  |  | FULLXF  xfb;                    /* coordinate transform */ | 
| 61 |  |  | short   drawcode;               /* drawing code */ | 
| 62 |  |  | short   xfac;                   /* transform argument count */ | 
| 63 |  |  | char    *xfav[MAXAC+1];         /* transform args */ | 
| 64 |  |  | } DOBJECT;                      /* a displayable object */ | 
| 65 |  |  |  | 
| 66 |  |  | static DLIGHTS  *dlightsets;            /* lighting sets */ | 
| 67 |  |  | static DOBJECT  *dobjects;              /* display object list */ | 
| 68 |  |  | static DOBJECT  *curobj;                /* current (last referred) object */ | 
| 69 |  |  | static int      lastxfac;               /* last number of transform args */ | 
| 70 |  |  | static char     *lastxfav[MAXAC+1];     /* saved transform arguments */ | 
| 71 |  |  |  | 
| 72 | gwlarson | 3.2 | #define getdcent(c,op)  multp3(c,(op)->center,(op)->xfb.f.xfm) | 
| 73 |  |  | #define getdrad(op)     ((op)->radius*(op)->xfb.f.sca) | 
| 74 |  |  |  | 
| 75 | gwlarson | 3.1 | #define RTARGC  8 | 
| 76 |  |  | static char     *rtargv[RTARGC+1] = {"rtrace", "-h-", "-w-", "-fdd", | 
| 77 |  |  | "-x", "1", "-oL"}; | 
| 78 |  |  |  | 
| 79 |  |  | static struct { | 
| 80 |  |  | int     nsamp;                  /* number of ray samples */ | 
| 81 |  |  | COLOR   val;                    /* value (sum) */ | 
| 82 |  |  | } ssamp[NALT][NAZI];            /* current sphere samples */ | 
| 83 |  |  |  | 
| 84 |  |  | #define curname         (curobj==NULL ? (char *)NULL : curobj->name) | 
| 85 |  |  |  | 
| 86 |  |  |  | 
| 87 |  |  | static DOBJECT * | 
| 88 |  |  | getdobj(nm)                     /* get object from list by name */ | 
| 89 |  |  | char    *nm; | 
| 90 |  |  | { | 
| 91 |  |  | register DOBJECT        *op; | 
| 92 |  |  |  | 
| 93 |  |  | if (nm == NULL) | 
| 94 |  |  | return(NULL); | 
| 95 |  |  | if (nm == curname) | 
| 96 |  |  | return(curobj); | 
| 97 |  |  | for (op = dobjects; op != NULL; op = op->next) | 
| 98 |  |  | if (!strcmp(op->name, nm)) | 
| 99 |  |  | break; | 
| 100 |  |  | return(op); | 
| 101 |  |  | } | 
| 102 |  |  |  | 
| 103 |  |  |  | 
| 104 |  |  | static | 
| 105 |  |  | freedobj(op)                    /* free resources and memory assoc. with op */ | 
| 106 |  |  | register DOBJECT        *op; | 
| 107 |  |  | { | 
| 108 |  |  | int     foundlink = 0; | 
| 109 |  |  | DOBJECT ohead; | 
| 110 |  |  | register DOBJECT        *opl; | 
| 111 |  |  |  | 
| 112 |  |  | if (op == NULL) | 
| 113 |  |  | return(0); | 
| 114 |  |  | ohead.next = dobjects; | 
| 115 |  |  | for (opl = &ohead; opl->next != NULL; opl = opl->next) { | 
| 116 |  |  | if (opl->next == op && (opl->next = op->next) == NULL) | 
| 117 |  |  | break; | 
| 118 |  |  | foundlink += opl->next->listid == op->listid; | 
| 119 |  |  | } | 
| 120 |  |  | dobjects = ohead.next; | 
| 121 |  |  | if (!foundlink) { | 
| 122 |  |  | glDeleteLists(op->listid, 1); | 
| 123 |  |  | close_process(op->rtp); | 
| 124 |  |  | } | 
| 125 |  |  | while (op->xfac) | 
| 126 |  |  | freestr(op->xfav[--op->xfac]); | 
| 127 |  |  | free((char *)op); | 
| 128 |  |  | return(1); | 
| 129 |  |  | } | 
| 130 |  |  |  | 
| 131 |  |  |  | 
| 132 |  |  | static | 
| 133 |  |  | savedxf(op)                     /* save transform for display object */ | 
| 134 |  |  | register DOBJECT        *op; | 
| 135 |  |  | { | 
| 136 |  |  | /* free old */ | 
| 137 |  |  | while (lastxfac) | 
| 138 |  |  | freestr(lastxfav[--lastxfac]); | 
| 139 |  |  | /* nothing to save? */ | 
| 140 |  |  | if (op == NULL) { | 
| 141 |  |  | lastxfav[0] = NULL; | 
| 142 |  |  | return(0); | 
| 143 |  |  | } | 
| 144 |  |  | /* else save new */ | 
| 145 |  |  | for (lastxfac = 0; lastxfac < op->xfac; lastxfac++) | 
| 146 |  |  | lastxfav[lastxfac] = savestr(op->xfav[lastxfac]); | 
| 147 |  |  | lastxfav[lastxfac] = NULL; | 
| 148 |  |  | return(1); | 
| 149 |  |  | } | 
| 150 |  |  |  | 
| 151 |  |  |  | 
| 152 |  |  | static | 
| 153 |  |  | ssph_sample(clr, direc, pos)    /* add sample to current source sphere */ | 
| 154 |  |  | COLR    clr; | 
| 155 |  |  | FVECT   direc, pos; | 
| 156 |  |  | { | 
| 157 |  |  | COLOR   col; | 
| 158 |  |  | double  d; | 
| 159 |  |  | register int    alt, azi; | 
| 160 |  |  |  | 
| 161 |  |  | if (dlightsets == NULL) | 
| 162 |  |  | return; | 
| 163 |  |  | if (pos == NULL) | 
| 164 |  |  | d = FHUGE;              /* sample is at infinity */ | 
| 165 |  |  | else if ((d = (pos[0] - dlightsets->lcent[0])*direc[0] + | 
| 166 |  |  | (pos[1] - dlightsets->lcent[1])*direc[1] + | 
| 167 |  |  | (pos[2] - dlightsets->lcent[2])*direc[2]) > FTINY) | 
| 168 |  |  | dlightsets->ravg += 1./d; | 
| 169 |  |  | else | 
| 170 |  |  | return;                 /* sample is behind us */ | 
| 171 |  |  | alt = NALT*(1.-FTINY)*(.5*(1.+FTINY) + direc[2]*.5); | 
| 172 |  |  | azi = NAZI*(1.-FTINY)*(.5*(1.+FTINY) + .5/PI*atan2(direc[1],direc[0])); | 
| 173 |  |  | colr_color(col, clr); | 
| 174 |  |  | addcolor(ssamp[alt][azi].val, col); | 
| 175 |  |  | ssamp[alt][azi].nsamp++; | 
| 176 |  |  | } | 
| 177 |  |  |  | 
| 178 |  |  |  | 
| 179 |  |  | static | 
| 180 |  |  | ssph_direc(direc, alt, azi)     /* compute sphere sampling direction */ | 
| 181 |  |  | FVECT   direc; | 
| 182 |  |  | int     alt, azi; | 
| 183 |  |  | { | 
| 184 |  |  | double  phi, d; | 
| 185 |  |  |  | 
| 186 |  |  | direc[2] = 2./NALT*(alt+.5) - 1.; | 
| 187 |  |  | d = sqrt(1. - direc[2]*direc[2]); | 
| 188 |  |  | phi = 2.*PI/NAZI*(azi+.5) - PI; | 
| 189 |  |  | direc[0] = d*cos(phi); | 
| 190 |  |  | direc[1] = d*sin(phi); | 
| 191 |  |  | } | 
| 192 |  |  |  | 
| 193 |  |  |  | 
| 194 |  |  | static int | 
| 195 |  |  | ssph_neigh(sp, next)            /* neighbor counter on sphere */ | 
| 196 |  |  | register int    sp[2]; | 
| 197 |  |  | int     next; | 
| 198 |  |  | { | 
| 199 |  |  | static short    nneigh = 0;             /* neighbor count */ | 
| 200 |  |  | static short    neighlist[NAZI+6][2];   /* neighbor list (0 is home) */ | 
| 201 |  |  | register int    i; | 
| 202 |  |  |  | 
| 203 |  |  | if (next) { | 
| 204 |  |  | if (nneigh <= 0) | 
| 205 |  |  | return(0); | 
| 206 |  |  | sp[0] = neighlist[--nneigh][0]; | 
| 207 |  |  | sp[1] = neighlist[nneigh][1]; | 
| 208 |  |  | return(1); | 
| 209 |  |  | } | 
| 210 |  |  | if (sp[0] < 0 | sp[0] >= NALT | sp[1] < 0 | sp[1] >= NAZI) | 
| 211 |  |  | return(nneigh=0); | 
| 212 |  |  | neighlist[0][0] = sp[0]; neighlist[0][1] = sp[1]; | 
| 213 |  |  | nneigh = 1; | 
| 214 |  |  | if (sp[0] == 0) { | 
| 215 |  |  | neighlist[nneigh][0] = 1; | 
| 216 |  |  | neighlist[nneigh++][1] = (sp[1]+1)%NAZI; | 
| 217 |  |  | neighlist[nneigh][0] = 1; | 
| 218 |  |  | neighlist[nneigh++][1] = sp[1]; | 
| 219 |  |  | neighlist[nneigh][0] = 1; | 
| 220 |  |  | neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI; | 
| 221 |  |  | for (i = 0; i < NAZI; i++) | 
| 222 |  |  | if (i != sp[1]) { | 
| 223 |  |  | neighlist[nneigh][0] = 0; | 
| 224 |  |  | neighlist[nneigh++][1] = i; | 
| 225 |  |  | } | 
| 226 |  |  | } else if (sp[0] == NALT-1) { | 
| 227 |  |  | neighlist[nneigh][0] = NALT-2; | 
| 228 |  |  | neighlist[nneigh++][1] = (sp[1]+1)%NAZI; | 
| 229 |  |  | neighlist[nneigh][0] = NALT-2; | 
| 230 |  |  | neighlist[nneigh++][1] = sp[1]; | 
| 231 |  |  | neighlist[nneigh][0] = NALT-2; | 
| 232 |  |  | neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI; | 
| 233 |  |  | for (i = 0; i < NAZI; i++) | 
| 234 |  |  | if (i != sp[1]) { | 
| 235 |  |  | neighlist[nneigh][0] = NALT-1; | 
| 236 |  |  | neighlist[nneigh++][1] = i; | 
| 237 |  |  | } | 
| 238 |  |  | } else { | 
| 239 |  |  | neighlist[nneigh][0] = sp[0]-1; | 
| 240 |  |  | neighlist[nneigh++][1] = (sp[1]+1)%NAZI; | 
| 241 |  |  | neighlist[nneigh][0] = sp[0]-1; | 
| 242 |  |  | neighlist[nneigh++][1] = sp[1]; | 
| 243 |  |  | neighlist[nneigh][0] = sp[0]-1; | 
| 244 |  |  | neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI; | 
| 245 |  |  | neighlist[nneigh][0] = sp[0]; | 
| 246 |  |  | neighlist[nneigh++][1] = (sp[1]+1)%NAZI; | 
| 247 |  |  | neighlist[nneigh][0] = sp[0]; | 
| 248 |  |  | neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI; | 
| 249 |  |  | neighlist[nneigh][0] = sp[0]+1; | 
| 250 |  |  | neighlist[nneigh++][1] = (sp[1]+1)%NAZI; | 
| 251 |  |  | neighlist[nneigh][0] = sp[0]+1; | 
| 252 |  |  | neighlist[nneigh++][1] = sp[1]; | 
| 253 |  |  | neighlist[nneigh][0] = sp[0]+1; | 
| 254 |  |  | neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI; | 
| 255 |  |  | } | 
| 256 |  |  | return(nneigh); | 
| 257 |  |  | } | 
| 258 |  |  |  | 
| 259 |  |  |  | 
| 260 |  |  | static | 
| 261 |  |  | ssph_compute()                  /* compute source set from sphere samples */ | 
| 262 |  |  | { | 
| 263 |  |  | int     ncells, nsamps; | 
| 264 |  |  | COLOR   csum; | 
| 265 |  |  | FVECT   v; | 
| 266 |  |  | double  d, thresh, maxbr; | 
| 267 |  |  | int     maxalt, maxazi, spos[2]; | 
| 268 |  |  | register int    alt, azi; | 
| 269 |  |  | register struct lsource *ls; | 
| 270 |  |  | /* count & average sampled cells */ | 
| 271 |  |  | setcolor(csum, 0., 0., 0.); | 
| 272 |  |  | ncells = nsamps = 0; | 
| 273 |  |  | for (alt = 0; alt < NALT; alt++) | 
| 274 |  |  | for (azi = 0; azi < NAZI; azi++) | 
| 275 |  |  | if (ssamp[alt][azi].nsamp) { | 
| 276 |  |  | if (ssamp[alt][azi].nsamp > 1) { | 
| 277 |  |  | d = 1.0/ssamp[alt][azi].nsamp; | 
| 278 |  |  | scalecolor(ssamp[alt][azi].val, d); | 
| 279 |  |  | } | 
| 280 |  |  | addcolor(csum, ssamp[alt][azi].val); | 
| 281 |  |  | nsamps += ssamp[alt][azi].nsamp; | 
| 282 |  |  | ncells++; | 
| 283 |  |  | } | 
| 284 |  |  | if (dlightsets == NULL | ncells < NALT*NAZI/4) { | 
| 285 | gwlarson | 3.2 | ncells = 0; | 
| 286 |  |  | goto done; | 
| 287 | gwlarson | 3.1 | } | 
| 288 |  |  | /* harmonic mean distance */ | 
| 289 |  |  | if (dlightsets->ravg > FTINY) | 
| 290 |  |  | dlightsets->ravg = nsamps / dlightsets->ravg; | 
| 291 |  |  | else | 
| 292 |  |  | dlightsets->ravg = FHUGE; | 
| 293 |  |  | /* light source threshold */ | 
| 294 |  |  | thresh = MINTHRESH*bright(csum)/ncells; | 
| 295 | gwlarson | 3.2 | if (thresh <= FTINY) { | 
| 296 |  |  | ncells = 0; | 
| 297 |  |  | goto done; | 
| 298 |  |  | } | 
| 299 | gwlarson | 3.1 | /* avg. reflected brightness */ | 
| 300 |  |  | d = AVGREFL / (double)ncells; | 
| 301 |  |  | scalecolor(csum, d); | 
| 302 |  |  | if (tmCvColors(&dlightsets->larb, TM_NOCHROM, csum, 1) != TM_E_OK) | 
| 303 | gwlarson | 3.2 | error(CONSISTENCY, "tone mapping problem in ssph_compute"); | 
| 304 | gwlarson | 3.1 | /* greedy light source clustering */ | 
| 305 |  |  | while (dlightsets->nl < MAXLIGHTS) { | 
| 306 |  |  | maxbr = 0.;                     /* find brightest cell */ | 
| 307 |  |  | for (alt = 0; alt < NALT; alt++) | 
| 308 |  |  | for (azi = 0; azi < NAZI; azi++) | 
| 309 |  |  | if ((d = bright(ssamp[alt][azi].val)) > maxbr) { | 
| 310 |  |  | maxalt = alt; maxazi = azi; | 
| 311 |  |  | maxbr = d; | 
| 312 |  |  | } | 
| 313 |  |  | if (maxbr < thresh)             /* below threshold? */ | 
| 314 |  |  | break; | 
| 315 |  |  | ls = dlightsets->li + dlightsets->nl++; | 
| 316 |  |  | spos[0] = maxalt; spos[1] = maxazi;     /* cluster */ | 
| 317 |  |  | for (ssph_neigh(spos, 0); ssph_neigh(spos, 1); ) { | 
| 318 |  |  | alt = spos[0]; azi = spos[1]; | 
| 319 |  |  | if ((d = bright(ssamp[alt][azi].val)) < .75*thresh) | 
| 320 |  |  | continue;               /* too dim */ | 
| 321 |  |  | ssph_direc(v, alt, azi);        /* else add it in */ | 
| 322 |  |  | VSUM(ls->direc, ls->direc, v, d); | 
| 323 | gwlarson | 3.6 | ls->omega += 1.; | 
| 324 | gwlarson | 3.1 | addcolor(ls->val, ssamp[alt][azi].val); | 
| 325 | gwlarson | 3.6 | /* remove from list */ | 
| 326 | gwlarson | 3.1 | setcolor(ssamp[alt][azi].val, 0., 0., 0.); | 
| 327 | gwlarson | 3.6 | ssamp[alt][azi].nsamp = 0; | 
| 328 | gwlarson | 3.1 | } | 
| 329 |  |  | d = 1./ls->omega;                       /* avg. brightness */ | 
| 330 |  |  | scalecolor(ls->val, d); | 
| 331 |  |  | ls->omega *= 4.*PI/(NALT*NAZI);         /* solid angle */ | 
| 332 |  |  | normalize(ls->direc);                   /* direction */ | 
| 333 |  |  | } | 
| 334 |  |  | /* compute ambient remainder */ | 
| 335 |  |  | for (alt = 0; alt < NALT; alt++) | 
| 336 |  |  | for (azi = 0; azi < NAZI; azi++) | 
| 337 |  |  | if (ssamp[alt][azi].nsamp) | 
| 338 |  |  | addcolor(dlightsets->lamb, ssamp[alt][azi].val); | 
| 339 |  |  | d = 1.0/ncells; | 
| 340 |  |  | scalecolor(dlightsets->lamb, d); | 
| 341 | gwlarson | 3.2 | done:                                   /* clear sphere sample array */ | 
| 342 | gwlarson | 3.1 | bzero((char *)ssamp, sizeof(ssamp)); | 
| 343 |  |  | return(ncells); | 
| 344 |  |  | } | 
| 345 |  |  |  | 
| 346 |  |  |  | 
| 347 |  |  | static | 
| 348 |  |  | getdlights(op, force)           /* get lights for display object */ | 
| 349 |  |  | register DOBJECT        *op; | 
| 350 |  |  | int     force; | 
| 351 |  |  | { | 
| 352 |  |  | double  d2, mind2 = FHUGE*FHUGE; | 
| 353 |  |  | FVECT   ocent; | 
| 354 |  |  | VIEW    cvw; | 
| 355 |  |  | register DLIGHTS        *dl; | 
| 356 |  |  |  | 
| 357 |  |  | op->ol = NULL; | 
| 358 |  |  | if (op->drawcode != DO_LIGHT) | 
| 359 |  |  | return(0); | 
| 360 |  |  | /* check for usable light set */ | 
| 361 | gwlarson | 3.2 | getdcent(ocent, op); | 
| 362 | gwlarson | 3.1 | for (dl = dlightsets; dl != NULL; dl = dl->next) | 
| 363 |  |  | if ((d2 = dist2(dl->lcent, ocent)) < mind2) { | 
| 364 |  |  | op->ol = dl; | 
| 365 |  |  | mind2 = d2; | 
| 366 |  |  | } | 
| 367 |  |  | /* the following is heuristic */ | 
| 368 | gwlarson | 3.2 | d2 = 2.*getdrad(op); d2 *= d2; | 
| 369 | gwlarson | 3.1 | if ((dl = op->ol) != NULL && (mind2 < 0.0625*dl->ravg*dl->ravg || | 
| 370 | gwlarson | 3.2 | mind2 < 4.*getdrad(op)*getdrad(op))) | 
| 371 | gwlarson | 3.1 | return(1); | 
| 372 |  |  | if (!force) | 
| 373 |  |  | return(0); | 
| 374 |  |  | /* need to compute new light set */ | 
| 375 |  |  | copystruct(&cvw, &stdview); | 
| 376 |  |  | cvw.type = VT_PER; | 
| 377 |  |  | VCOPY(cvw.vp, ocent); | 
| 378 |  |  | cvw.vup[0] = 1.; cvw.vup[1] = cvw.vup[2] = 0.; | 
| 379 |  |  | cvw.horiz = 90; cvw.vert = 90.; | 
| 380 |  |  | beam_init(1);                   /* query beams through center */ | 
| 381 |  |  | cvw.vdir[0] = cvw.vdir[1] = 0.; cvw.vdir[2] = 1.; | 
| 382 |  |  | setview(&cvw); beam_view(&cvw, 0, 0); | 
| 383 |  |  | cvw.vdir[0] = cvw.vdir[1] = 0.; cvw.vdir[2] = -1.; | 
| 384 |  |  | setview(&cvw); beam_view(&cvw, 0, 0); | 
| 385 |  |  | cvw.vup[0] = cvw.vup[1] = 0.; cvw.vup[2] = 1.; | 
| 386 |  |  | cvw.vdir[0] = cvw.vdir[2] = 0.; cvw.vdir[1] = 1.; | 
| 387 |  |  | setview(&cvw); beam_view(&cvw, 0, 0); | 
| 388 |  |  | cvw.vdir[0] = cvw.vdir[2] = 0.; cvw.vdir[1] = -1.; | 
| 389 |  |  | setview(&cvw); beam_view(&cvw, 0, 0); | 
| 390 |  |  | cvw.vdir[1] = cvw.vdir[2] = 0.; cvw.vdir[0] = 1.; | 
| 391 |  |  | setview(&cvw); beam_view(&cvw, 0, 0); | 
| 392 |  |  | cvw.vdir[1] = cvw.vdir[2] = 0.; cvw.vdir[0] = -1.; | 
| 393 |  |  | setview(&cvw); beam_view(&cvw, 0, 0); | 
| 394 |  |  | /* allocate new light set */ | 
| 395 |  |  | dl = (DLIGHTS *)calloc(1, sizeof(DLIGHTS)); | 
| 396 |  |  | if (dl == NULL) | 
| 397 |  |  | goto memerr; | 
| 398 |  |  | VCOPY(dl->lcent, ocent); | 
| 399 |  |  | /* push onto our light set list */ | 
| 400 |  |  | dl->next = dlightsets; | 
| 401 |  |  | dlightsets = dl; | 
| 402 |  |  | dobj_lightsamp = ssph_sample;   /* get beams from server */ | 
| 403 |  |  | imm_mode = beam_sync(-1) > 0; | 
| 404 |  |  | while (imm_mode) | 
| 405 |  |  | if (serv_result() == DS_SHUTDOWN) | 
| 406 |  |  | quit(0); | 
| 407 |  |  | if (!ssph_compute()) {          /* compute light sources from sphere */ | 
| 408 |  |  | dlightsets = dl->next; | 
| 409 |  |  | free((char *)dl); | 
| 410 |  |  | return(0); | 
| 411 |  |  | } | 
| 412 |  |  | op->ol = dl; | 
| 413 |  |  | return(1); | 
| 414 |  |  | memerr: | 
| 415 |  |  | error(SYSTEM, "out of memory in getdlights"); | 
| 416 |  |  | } | 
| 417 |  |  |  | 
| 418 |  |  |  | 
| 419 |  |  | static int | 
| 420 |  |  | cmderror(cn, err)               /* report command error */ | 
| 421 |  |  | int     cn; | 
| 422 |  |  | char    *err; | 
| 423 |  |  | { | 
| 424 |  |  | sprintf(errmsg, "%s: %s", rhdcmd[cn], err); | 
| 425 |  |  | error(COMMAND, errmsg); | 
| 426 |  |  | return(cn); | 
| 427 |  |  | } | 
| 428 |  |  |  | 
| 429 |  |  |  | 
| 430 |  |  | int | 
| 431 |  |  | dobj_command(cmd, args)         /* run object display command */ | 
| 432 |  |  | char    *cmd; | 
| 433 |  |  | register char   *args; | 
| 434 |  |  | { | 
| 435 |  |  | int     cn, na, doxfm; | 
| 436 |  |  | register int    nn; | 
| 437 |  |  | char    *alist[MAXAC+1], *nm; | 
| 438 |  |  | /* find command */ | 
| 439 |  |  | for (cn = 0; cn < DO_NCMDS; cn++) | 
| 440 |  |  | if (!strcmp(cmd, rhdcmd[cn])) | 
| 441 |  |  | break; | 
| 442 |  |  | if (cn >= DO_NCMDS) | 
| 443 |  |  | return(-1);             /* not in our list */ | 
| 444 |  |  | /* make argument list */ | 
| 445 |  |  | for (na = 0; *args; na++) { | 
| 446 |  |  | if (na > MAXAC) | 
| 447 |  |  | goto toomany; | 
| 448 |  |  | alist[na] = args; | 
| 449 |  |  | while (*args && !isspace(*args)) | 
| 450 |  |  | args++; | 
| 451 |  |  | while (isspace(*args)) | 
| 452 |  |  | *args++ = '\0'; | 
| 453 |  |  | } | 
| 454 |  |  | alist[na] = NULL; | 
| 455 |  |  | /* execute command */ | 
| 456 |  |  | switch (cn) { | 
| 457 |  |  | case DO_LOAD:                           /* load an octree */ | 
| 458 |  |  | if (na == 1) | 
| 459 |  |  | dobj_load(alist[0], alist[0]); | 
| 460 |  |  | else if (na == 2) | 
| 461 |  |  | dobj_load(alist[0], alist[1]); | 
| 462 |  |  | else | 
| 463 |  |  | return(cmderror(cn, "need octree [name]")); | 
| 464 |  |  | break; | 
| 465 | gwlarson | 3.5 | case DO_UNLOAD:                         /* clear an object */ | 
| 466 | gwlarson | 3.1 | if (na > 1) goto toomany; | 
| 467 |  |  | if (na && alist[0][0] == '*') | 
| 468 |  |  | dobj_cleanup(); | 
| 469 |  |  | else | 
| 470 |  |  | dobj_unload(na ? alist[0] : curname); | 
| 471 |  |  | break; | 
| 472 |  |  | case DO_XFORM:                          /* transform object */ | 
| 473 |  |  | case DO_MOVE: | 
| 474 |  |  | if (na && alist[0][0] != '-') { | 
| 475 |  |  | nm = alist[0]; nn = 1; | 
| 476 |  |  | } else { | 
| 477 |  |  | nm = curname; nn = 0; | 
| 478 |  |  | } | 
| 479 |  |  | if (cn == DO_MOVE && nn >= na) | 
| 480 |  |  | return(cmderror(cn, "missing transform")); | 
| 481 |  |  | dobj_xform(nm, cn==DO_MOVE, na-nn, alist+nn); | 
| 482 |  |  | break; | 
| 483 |  |  | case DO_UNMOVE:                         /* undo last transform */ | 
| 484 |  |  | dobj_unmove(); | 
| 485 |  |  | break; | 
| 486 |  |  | case DO_OBJECT:                         /* print object statistics */ | 
| 487 | gwlarson | 3.3 | if (dobj_putstats(na ? alist[0] : curname, sstdout)) | 
| 488 | gwlarson | 3.5 | if (na && alist[0][0] != '*' && (curobj == NULL || | 
| 489 |  |  | strcmp(alist[0], curobj->name))) | 
| 490 | gwlarson | 3.3 | savedxf(curobj = getdobj(alist[0])); | 
| 491 | gwlarson | 3.1 | break; | 
| 492 |  |  | case DO_DUP:                            /* duplicate object */ | 
| 493 |  |  | for (nn = 0; nn < na; nn++) | 
| 494 |  |  | if (alist[nn][0] == '-') | 
| 495 |  |  | break; | 
| 496 |  |  | switch (nn) { | 
| 497 |  |  | case 0: | 
| 498 |  |  | return(cmderror(cn, "need new object name")); | 
| 499 |  |  | case 1: | 
| 500 |  |  | nm = curname; | 
| 501 |  |  | break; | 
| 502 |  |  | case 2: | 
| 503 |  |  | nm = alist[0]; | 
| 504 |  |  | break; | 
| 505 |  |  | default: | 
| 506 |  |  | goto toomany; | 
| 507 |  |  | } | 
| 508 |  |  | if (!dobj_dup(nm, alist[nn-1])) | 
| 509 |  |  | break; | 
| 510 |  |  | if (na > nn) | 
| 511 |  |  | dobj_xform(curname, 1, na-nn, alist+nn); | 
| 512 |  |  | else | 
| 513 |  |  | curobj->drawcode = DO_HIDE; | 
| 514 | gwlarson | 3.3 | savedxf(curobj); | 
| 515 | gwlarson | 3.1 | break; | 
| 516 |  |  | case DO_SHOW:                           /* change rendering option */ | 
| 517 |  |  | case DO_LIGHT: | 
| 518 |  |  | case DO_HIDE: | 
| 519 |  |  | if (na > 1) goto toomany; | 
| 520 |  |  | dobj_lighting(na ? alist[0] : curname, cn); | 
| 521 |  |  | break; | 
| 522 |  |  | default: | 
| 523 |  |  | error(CONSISTENCY, "bad command id in dobj_command"); | 
| 524 |  |  | } | 
| 525 |  |  | dev_view(&odev.v);                      /* redraw */ | 
| 526 |  |  | return(cn); | 
| 527 |  |  | toomany: | 
| 528 |  |  | return(cmderror(cn, "too many arguments")); | 
| 529 |  |  | } | 
| 530 |  |  |  | 
| 531 |  |  |  | 
| 532 |  |  | dobj_load(oct, nam)             /* create/load an octree object */ | 
| 533 |  |  | char    *oct, *nam; | 
| 534 |  |  | { | 
| 535 |  |  | extern char     *getlibpath(), *getpath(); | 
| 536 |  |  | char    *fpp, fpath[128]; | 
| 537 |  |  | register DOBJECT        *op; | 
| 538 |  |  | /* check arguments */ | 
| 539 |  |  | if (oct == NULL) { | 
| 540 |  |  | error(COMMAND, "missing octree"); | 
| 541 |  |  | return(0); | 
| 542 |  |  | } | 
| 543 |  |  | if (nam == NULL) { | 
| 544 |  |  | error(COMMAND, "missing name"); | 
| 545 |  |  | return(0); | 
| 546 |  |  | } | 
| 547 |  |  | if (*nam == '*' | *nam == '-') { | 
| 548 |  |  | error(COMMAND, "illegal name"); | 
| 549 |  |  | return(0); | 
| 550 |  |  | } | 
| 551 | gwlarson | 3.3 | if (getdobj(nam) != NULL) { | 
| 552 | gwlarson | 3.5 | error(COMMAND, "name already taken (clear first)"); | 
| 553 | gwlarson | 3.3 | return(0); | 
| 554 |  |  | } | 
| 555 | gwlarson | 3.1 | /* get octree path */ | 
| 556 |  |  | if ((fpp = getpath(oct, getlibpath(), R_OK)) == NULL) { | 
| 557 |  |  | sprintf(errmsg, "cannot find octree \"%s\"", oct); | 
| 558 |  |  | error(COMMAND, errmsg); | 
| 559 |  |  | return(0); | 
| 560 |  |  | } | 
| 561 |  |  | strcpy(fpath, fpp); | 
| 562 |  |  | op = (DOBJECT *)malloc(sizeof(DOBJECT)); | 
| 563 |  |  | if (op == NULL) | 
| 564 |  |  | error(SYSTEM, "out of memory in dobj_load"); | 
| 565 |  |  | /* set struct fields */ | 
| 566 |  |  | strcpy(op->name, nam); | 
| 567 |  |  | op->ol = NULL; | 
| 568 |  |  | op->drawcode = DO_HIDE; | 
| 569 |  |  | setident4(op->xfb.f.xfm); op->xfb.f.sca = 1.; | 
| 570 |  |  | setident4(op->xfb.b.xfm); op->xfb.b.sca = 1.; | 
| 571 |  |  | op->xfav[op->xfac=0] = NULL; | 
| 572 |  |  | /* load octree into display list */ | 
| 573 |  |  | dolights = 0; | 
| 574 |  |  | op->listid = rgl_octlist(fpath, op->center, &op->radius); | 
| 575 |  |  | /* start rtrace */ | 
| 576 |  |  | rtargv[RTARGC-1] = fpath; | 
| 577 |  |  | rtargv[RTARGC] = NULL; | 
| 578 |  |  | open_process(op->rtp, rtargv); | 
| 579 |  |  | /* insert into main list */ | 
| 580 |  |  | op->next = dobjects; | 
| 581 |  |  | curobj = dobjects = op; | 
| 582 |  |  | savedxf(NULL); | 
| 583 |  |  | return(1); | 
| 584 |  |  | } | 
| 585 |  |  |  | 
| 586 |  |  |  | 
| 587 |  |  | dobj_unload(nam)                        /* free the named object */ | 
| 588 |  |  | char    *nam; | 
| 589 |  |  | { | 
| 590 |  |  | register DOBJECT        *op; | 
| 591 |  |  |  | 
| 592 |  |  | if ((op = getdobj(nam)) == NULL) { | 
| 593 |  |  | error(COMMAND, "no object"); | 
| 594 |  |  | return(0); | 
| 595 |  |  | } | 
| 596 |  |  | freedobj(op); | 
| 597 |  |  | savedxf(curobj = NULL); | 
| 598 |  |  | return(1); | 
| 599 |  |  | } | 
| 600 |  |  |  | 
| 601 |  |  |  | 
| 602 |  |  | dobj_cleanup()                          /* free all resources */ | 
| 603 |  |  | { | 
| 604 |  |  | register DLIGHTS        *lp; | 
| 605 |  |  |  | 
| 606 |  |  | while (dobjects != NULL) | 
| 607 |  |  | freedobj(dobjects); | 
| 608 |  |  | savedxf(curobj = NULL); | 
| 609 |  |  | while ((lp = dlightsets) != NULL) { | 
| 610 |  |  | dlightsets = lp->next; | 
| 611 |  |  | free((char *)lp); | 
| 612 |  |  | } | 
| 613 |  |  | return(1); | 
| 614 |  |  | } | 
| 615 |  |  |  | 
| 616 |  |  |  | 
| 617 | gwlarson | 3.6 | dobj_xform(nam, rel, ac, av)            /* set/add transform for nam */ | 
| 618 | gwlarson | 3.1 | char    *nam; | 
| 619 | gwlarson | 3.6 | int     rel, ac; | 
| 620 | gwlarson | 3.1 | char    **av; | 
| 621 |  |  | { | 
| 622 |  |  | register DOBJECT        *op; | 
| 623 | gwlarson | 3.6 | FVECT   cent; | 
| 624 |  |  | double  rad; | 
| 625 |  |  | char    scoord[16]; | 
| 626 |  |  | int     i; | 
| 627 | gwlarson | 3.1 |  | 
| 628 |  |  | if ((op = getdobj(nam)) == NULL) { | 
| 629 |  |  | error(COMMAND, "no object"); | 
| 630 |  |  | return(0); | 
| 631 |  |  | } | 
| 632 | gwlarson | 3.6 | if (rel) | 
| 633 |  |  | rel = op->xfac + 8; | 
| 634 |  |  | if (ac + rel > MAXAC) { | 
| 635 | gwlarson | 3.1 | error(COMMAND, "too many transform arguments"); | 
| 636 |  |  | return(0); | 
| 637 |  |  | } | 
| 638 | gwlarson | 3.6 | savedxf(curobj = op);           /* remember current transform */ | 
| 639 |  |  | if (rel && ac == 4 && !strcmp(av[0], "-t")) | 
| 640 |  |  | rel = -1;                       /* don't move for translate */ | 
| 641 |  |  | else { | 
| 642 |  |  | getdcent(cent, op);             /* don't move if near orig. */ | 
| 643 |  |  | rad = getdrad(op); | 
| 644 |  |  | if (DOT(cent,cent) < rad*rad) | 
| 645 |  |  | rel = -1; | 
| 646 |  |  | } | 
| 647 |  |  | if (!rel) {                             /* remove old transform */ | 
| 648 | gwlarson | 3.1 | while (op->xfac) | 
| 649 |  |  | freestr(op->xfav[--op->xfac]); | 
| 650 | gwlarson | 3.6 | } else if (rel > 0) {                   /* relative move */ | 
| 651 |  |  | op->xfav[op->xfac++] = savestr("-t"); | 
| 652 |  |  | for (i = 0; i < 3; i++) { | 
| 653 |  |  | sprintf(scoord, "%.4e", -cent[i]); | 
| 654 |  |  | op->xfav[op->xfac++] = savestr(scoord); | 
| 655 |  |  | } | 
| 656 |  |  | } | 
| 657 | gwlarson | 3.1 | while (ac--) | 
| 658 |  |  | op->xfav[op->xfac++] = savestr(*av++); | 
| 659 | gwlarson | 3.6 | if (rel > 0) {                          /* move back */ | 
| 660 |  |  | op->xfav[op->xfac++] = savestr("-t"); | 
| 661 |  |  | for (i = 0; i < 3; i++) { | 
| 662 |  |  | sprintf(scoord, "%.4e", cent[i]); | 
| 663 |  |  | op->xfav[op->xfac++] = savestr(scoord); | 
| 664 |  |  | } | 
| 665 |  |  | } | 
| 666 | gwlarson | 3.1 | op->xfav[op->xfac] = NULL; | 
| 667 |  |  | if (fullxf(&op->xfb, op->xfac, op->xfav) != op->xfac) { | 
| 668 |  |  | error(COMMAND, "bad transform arguments"); | 
| 669 |  |  | dobj_unmove(); | 
| 670 |  |  | savedxf(op);            /* save current transform instead */ | 
| 671 |  |  | return(0); | 
| 672 |  |  | } | 
| 673 |  |  | /* don't know local lights anymore */ | 
| 674 |  |  | getdlights(op, 0); | 
| 675 |  |  | return(1); | 
| 676 |  |  | } | 
| 677 |  |  |  | 
| 678 |  |  |  | 
| 679 |  |  | dobj_putstats(nam, fp)                  /* put out statistics for nam */ | 
| 680 |  |  | char    *nam; | 
| 681 |  |  | FILE    *fp; | 
| 682 |  |  | { | 
| 683 |  |  | FVECT   ocent; | 
| 684 |  |  | register DOBJECT        *op; | 
| 685 |  |  | register int    i; | 
| 686 |  |  |  | 
| 687 |  |  | if (nam == NULL) { | 
| 688 |  |  | error(COMMAND, "no current object"); | 
| 689 |  |  | return(0); | 
| 690 |  |  | } | 
| 691 |  |  | if (nam[0] == '*') { | 
| 692 |  |  | i = 0; | 
| 693 |  |  | for (op = dobjects; op != NULL; op = op->next) | 
| 694 |  |  | i += dobj_putstats(op->name, fp); | 
| 695 |  |  | return(i); | 
| 696 |  |  | } | 
| 697 |  |  | if ((op = getdobj(nam)) == NULL) { | 
| 698 |  |  | error(COMMAND, "unknown object"); | 
| 699 |  |  | return(0); | 
| 700 |  |  | } | 
| 701 | gwlarson | 3.2 | getdcent(ocent, op); | 
| 702 | gwlarson | 3.6 | fprintf(fp, "%s: %s, center [%g %g %g], radius %g", op->name, | 
| 703 | gwlarson | 3.3 | op->drawcode==DO_HIDE ? "hidden" : | 
| 704 |  |  | op->drawcode==DO_LIGHT && op->ol!=NULL ? "lighted" : | 
| 705 | gwlarson | 3.1 | "shown", | 
| 706 | gwlarson | 3.2 | ocent[0],ocent[1],ocent[2], getdrad(op)); | 
| 707 | gwlarson | 3.1 | if (op->xfac) | 
| 708 |  |  | fputs(", (xform", fp); | 
| 709 |  |  | for (i = 0; i < op->xfac; i++) { | 
| 710 |  |  | putc(' ', fp); | 
| 711 |  |  | fputs(op->xfav[i], fp); | 
| 712 |  |  | } | 
| 713 |  |  | if (op->xfac) | 
| 714 |  |  | fputc(')', fp); | 
| 715 |  |  | fputc('\n', fp); | 
| 716 |  |  | return(1); | 
| 717 |  |  | } | 
| 718 |  |  |  | 
| 719 |  |  |  | 
| 720 |  |  | dobj_unmove()                           /* undo last transform change */ | 
| 721 |  |  | { | 
| 722 |  |  | int     txfac; | 
| 723 |  |  | char    *txfav[MAXAC+1]; | 
| 724 |  |  |  | 
| 725 |  |  | if (curobj == NULL) { | 
| 726 |  |  | error(COMMAND, "no current object"); | 
| 727 |  |  | return(0); | 
| 728 |  |  | } | 
| 729 |  |  | /* hold last transform */ | 
| 730 |  |  | bcopy((char *)lastxfav, (char *)txfav, | 
| 731 |  |  | (txfac=lastxfac)*sizeof(char *)); | 
| 732 |  |  | /* save this transform */ | 
| 733 |  |  | bcopy((char *)curobj->xfav, (char *)lastxfav, | 
| 734 |  |  | (lastxfac=curobj->xfac)*sizeof(char *)); | 
| 735 |  |  | /* copy back last transform */ | 
| 736 |  |  | bcopy((char *)txfav, (char *)curobj->xfav, | 
| 737 |  |  | (curobj->xfac=txfac)*sizeof(char *)); | 
| 738 |  |  | /* set matrices */ | 
| 739 |  |  | fullxf(&curobj->xfb, curobj->xfac, curobj->xfav); | 
| 740 |  |  | /* don't know local lights anymore */ | 
| 741 |  |  | getdlights(curobj, 0); | 
| 742 |  |  | return(1); | 
| 743 |  |  | } | 
| 744 |  |  |  | 
| 745 |  |  |  | 
| 746 |  |  | dobj_dup(oldnm, nam)                    /* duplicate object oldnm as nam */ | 
| 747 |  |  | char    *oldnm, *nam; | 
| 748 |  |  | { | 
| 749 |  |  | register DOBJECT        *op, *opdup; | 
| 750 |  |  | /* check arguments */ | 
| 751 |  |  | if ((op = getdobj(oldnm)) == NULL) { | 
| 752 |  |  | error(COMMAND, "no object"); | 
| 753 |  |  | return(0); | 
| 754 |  |  | } | 
| 755 |  |  | if (nam == NULL) { | 
| 756 |  |  | error(COMMAND, "missing name"); | 
| 757 |  |  | return(0); | 
| 758 |  |  | } | 
| 759 |  |  | if (*nam == '*' | *nam == '-') { | 
| 760 |  |  | error(COMMAND, "illegal name"); | 
| 761 |  |  | return(0); | 
| 762 |  |  | } | 
| 763 | gwlarson | 3.3 | if (getdobj(nam) != NULL) { | 
| 764 | gwlarson | 3.5 | error(COMMAND, "name already taken (clear first)"); | 
| 765 | gwlarson | 3.3 | return(0); | 
| 766 |  |  | } | 
| 767 | gwlarson | 3.1 | /* allocate and copy struct */ | 
| 768 |  |  | opdup = (DOBJECT *)malloc(sizeof(DOBJECT)); | 
| 769 |  |  | if (opdup == NULL) | 
| 770 |  |  | error(SYSTEM, "out of memory in dobj_dup"); | 
| 771 |  |  | copystruct(opdup, op); | 
| 772 |  |  | /* rename */ | 
| 773 |  |  | strcpy(opdup->name, nam); | 
| 774 |  |  | /* get our own copy of transform */ | 
| 775 |  |  | for (opdup->xfac = 0; opdup->xfac < op->xfac; opdup->xfac++) | 
| 776 |  |  | opdup->xfav[opdup->xfac] = savestr(op->xfav[opdup->xfac]); | 
| 777 |  |  | opdup->xfav[opdup->xfac] = NULL; | 
| 778 |  |  | /* insert it into our list */ | 
| 779 |  |  | opdup->next = dobjects; | 
| 780 |  |  | curobj = dobjects = opdup; | 
| 781 |  |  | return(1); | 
| 782 |  |  | } | 
| 783 |  |  |  | 
| 784 |  |  |  | 
| 785 |  |  | dobj_lighting(nam, cn)          /* set up lighting for display object */ | 
| 786 |  |  | char    *nam; | 
| 787 |  |  | int     cn; | 
| 788 |  |  | { | 
| 789 |  |  | int     i, res[2]; | 
| 790 |  |  | VIEW    *dv; | 
| 791 |  |  | register DOBJECT        *op; | 
| 792 |  |  |  | 
| 793 |  |  | if (nam == NULL) { | 
| 794 |  |  | error(COMMAND, "no current object"); | 
| 795 |  |  | return(0); | 
| 796 |  |  | } | 
| 797 |  |  | if (nam[0] == '*') { | 
| 798 |  |  | for (op = dobjects; op != NULL; op = op->next) | 
| 799 |  |  | if ((op->drawcode = cn) == DO_LIGHT) | 
| 800 |  |  | getdlights(op, 1); | 
| 801 |  |  | else | 
| 802 |  |  | op->ol = NULL; | 
| 803 |  |  | } else if ((op = getdobj(nam)) == NULL) { | 
| 804 |  |  | error(COMMAND, "unknown object"); | 
| 805 |  |  | return(0); | 
| 806 | gwlarson | 3.4 | } else if ((op->drawcode = cn) == DO_LIGHT) { | 
| 807 |  |  | if (!getdlights(op, 1)) | 
| 808 |  |  | error(COMMAND, "insufficient samples to light object"); | 
| 809 |  |  | } else | 
| 810 | gwlarson | 3.1 | op->ol = NULL; | 
| 811 |  |  |  | 
| 812 |  |  | if (dobj_lightsamp != NULL) {           /* restore beam set */ | 
| 813 |  |  | dobj_lightsamp = NULL; | 
| 814 |  |  | beam_init(1); | 
| 815 |  |  | for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++) | 
| 816 |  |  | beam_view(dv, res[0], res[1]); | 
| 817 |  |  | beam_sync(1);                   /* update server */ | 
| 818 |  |  | } | 
| 819 |  |  | } | 
| 820 |  |  |  | 
| 821 |  |  |  | 
| 822 |  |  | double | 
| 823 | gwlarson | 3.2 | dobj_trace(nm, rorg, rdir)      /* check for ray intersection with object(s) */ | 
| 824 |  |  | char    nm[]; | 
| 825 | gwlarson | 3.1 | FVECT   rorg, rdir; | 
| 826 |  |  | { | 
| 827 |  |  | register DOBJECT        *op; | 
| 828 |  |  | FVECT   xorg, xdir; | 
| 829 | gwlarson | 3.2 | double  darr[6]; | 
| 830 | gwlarson | 3.3 | /* check each visible object? */ | 
| 831 | gwlarson | 3.2 | if (nm == NULL || *nm == '*') { | 
| 832 |  |  | double  dist, mindist = 1.01*FHUGE; | 
| 833 | gwlarson | 3.3 |  | 
| 834 |  |  | if (nm != NULL) nm[0] = '\0'; | 
| 835 | gwlarson | 3.2 | for (op = dobjects; op != NULL; op = op->next) { | 
| 836 |  |  | if (op->drawcode == DO_HIDE) | 
| 837 |  |  | continue; | 
| 838 |  |  | dist = dobj_trace(op->name, rorg, rdir); | 
| 839 |  |  | if (dist < mindist) { | 
| 840 | gwlarson | 3.3 | if (nm != NULL) strcpy(nm, op->name); | 
| 841 |  |  | mindist = dist; | 
| 842 | gwlarson | 3.2 | } | 
| 843 | gwlarson | 3.1 | } | 
| 844 | gwlarson | 3.2 | return(mindist); | 
| 845 | gwlarson | 3.1 | } | 
| 846 | gwlarson | 3.2 | /* else check particular object */ | 
| 847 |  |  | if ((op = getdobj(nm)) == NULL) { | 
| 848 |  |  | error(COMMAND, "unknown object"); | 
| 849 |  |  | return(FHUGE); | 
| 850 |  |  | } | 
| 851 | gwlarson | 3.3 | if (op->xfac) {         /* put ray in local coordinates */ | 
| 852 | gwlarson | 3.2 | multp3(xorg, rorg, op->xfb.b.xfm); | 
| 853 |  |  | multv3(xdir, rdir, op->xfb.b.xfm); | 
| 854 |  |  | VCOPY(darr, xorg); VCOPY(darr+3, xdir); | 
| 855 |  |  | } else { | 
| 856 |  |  | VCOPY(darr, rorg); VCOPY(darr+3, rdir); | 
| 857 |  |  | } | 
| 858 |  |  | /* trace it */ | 
| 859 |  |  | if (process(op->rtp, darr, darr, sizeof(double), | 
| 860 |  |  | 6*sizeof(double)) != sizeof(double)) | 
| 861 |  |  | error(SYSTEM, "rtrace communication error"); | 
| 862 |  |  | /* return distance */ | 
| 863 |  |  | if (darr[0] >= .99*FHUGE) | 
| 864 |  |  | return(FHUGE); | 
| 865 | gwlarson | 3.3 | return(darr[0]*op->xfb.f.sca); | 
| 866 | gwlarson | 3.1 | } | 
| 867 |  |  |  | 
| 868 |  |  |  | 
| 869 | gwlarson | 3.7 | int | 
| 870 | gwlarson | 3.1 | dobj_render()                   /* render our objects in OpenGL */ | 
| 871 |  |  | { | 
| 872 | gwlarson | 3.7 | int     nrendered = 0; | 
| 873 | gwlarson | 3.1 | GLboolean       normalizing; | 
| 874 |  |  | GLfloat vec[4]; | 
| 875 | gwlarson | 3.2 | FVECT   v1; | 
| 876 | gwlarson | 3.1 | register DOBJECT        *op; | 
| 877 |  |  | register int    i; | 
| 878 |  |  | /* anything to render? */ | 
| 879 |  |  | for (op = dobjects; op != NULL; op = op->next) | 
| 880 |  |  | if (op->drawcode != DO_HIDE) | 
| 881 |  |  | break; | 
| 882 |  |  | if (op == NULL) | 
| 883 | gwlarson | 3.7 | return(0); | 
| 884 | gwlarson | 3.1 | /* set up general rendering params */ | 
| 885 |  |  | glGetBooleanv(GL_NORMALIZE, &normalizing); | 
| 886 | gwlarson | 3.4 | glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT|GL_ENABLE_BIT| | 
| 887 |  |  | GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT); | 
| 888 | gwlarson | 3.1 | glDepthFunc(GL_LESS); | 
| 889 |  |  | glEnable(GL_DEPTH_TEST); | 
| 890 |  |  | glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); | 
| 891 |  |  | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | 
| 892 |  |  | glShadeModel(GL_SMOOTH); | 
| 893 |  |  | glFrontFace(GL_CCW); | 
| 894 |  |  | glDisable(GL_CULL_FACE); | 
| 895 |  |  | for (i = MAXLIGHTS; i--; ) | 
| 896 |  |  | glDisable(glightid[i]); | 
| 897 |  |  | glEnable(GL_LIGHTING); | 
| 898 |  |  | rgl_checkerr("setting rendering modes in dobj_render"); | 
| 899 |  |  | /* render each object */ | 
| 900 |  |  | for (op = dobjects; op != NULL; op = op->next) { | 
| 901 |  |  | if (op->drawcode == DO_HIDE) | 
| 902 |  |  | continue; | 
| 903 |  |  | /* set up lighting */ | 
| 904 |  |  | if (op->drawcode == DO_LIGHT && op->ol != NULL) { | 
| 905 |  |  | BYTE    pval; | 
| 906 |  |  | double  expval, d; | 
| 907 | gwlarson | 3.2 | /* use computed sources */ | 
| 908 | gwlarson | 3.1 | if (tmMapPixels(&pval, &op->ol->larb, TM_NOCHROM, 1) | 
| 909 |  |  | != TM_E_OK) | 
| 910 |  |  | error(CONSISTENCY, "dobj_render w/o tone map"); | 
| 911 |  |  | expval = pval * (WHTEFFICACY/256.) / | 
| 912 |  |  | tmLuminance(op->ol->larb); | 
| 913 |  |  | vec[0] = expval * colval(op->ol->lamb,RED); | 
| 914 |  |  | vec[1] = expval * colval(op->ol->lamb,GRN); | 
| 915 |  |  | vec[2] = expval * colval(op->ol->lamb,BLU); | 
| 916 |  |  | vec[3] = 1.; | 
| 917 |  |  | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec); | 
| 918 |  |  | for (i = op->ol->nl; i--; ) { | 
| 919 |  |  | VCOPY(vec, op->ol->li[i].direc); | 
| 920 |  |  | vec[3] = 0.; | 
| 921 |  |  | glLightfv(glightid[i], GL_POSITION, vec); | 
| 922 |  |  | d = expval * op->ol->li[i].omega; | 
| 923 |  |  | vec[0] = d * colval(op->ol->li[i].val,RED); | 
| 924 |  |  | vec[1] = d * colval(op->ol->li[i].val,GRN); | 
| 925 |  |  | vec[2] = d * colval(op->ol->li[i].val,BLU); | 
| 926 |  |  | vec[3] = 1.; | 
| 927 |  |  | glLightfv(glightid[i], GL_SPECULAR, vec); | 
| 928 |  |  | glLightfv(glightid[i], GL_DIFFUSE, vec); | 
| 929 |  |  | vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.; | 
| 930 |  |  | glLightfv(glightid[i], GL_AMBIENT, vec); | 
| 931 |  |  | glEnable(glightid[i]); | 
| 932 |  |  | } | 
| 933 | gwlarson | 3.3 | } else {                        /* fake lighting */ | 
| 934 | gwlarson | 3.2 | vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.; | 
| 935 | gwlarson | 3.1 | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec); | 
| 936 | gwlarson | 3.2 | getdcent(v1, op); | 
| 937 |  |  | VSUB(v1, odev.v.vp, v1); | 
| 938 |  |  | if (normalize(v1) <= getdrad(op)) { | 
| 939 |  |  | vec[0] = -odev.v.vdir[0]; | 
| 940 |  |  | vec[1] = -odev.v.vdir[1]; | 
| 941 |  |  | vec[2] = -odev.v.vdir[2]; | 
| 942 |  |  | } else | 
| 943 |  |  | VCOPY(vec, v1); | 
| 944 |  |  | vec[3] = 0.; | 
| 945 |  |  | glLightfv(GL_LIGHT0, GL_POSITION, vec); | 
| 946 |  |  | vec[0] = vec[1] = vec[2] = .7; vec[3] = 1.; | 
| 947 |  |  | glLightfv(GL_LIGHT0, GL_SPECULAR, vec); | 
| 948 |  |  | glLightfv(GL_LIGHT0, GL_DIFFUSE, vec); | 
| 949 |  |  | vec[0] = vec[1] = vec[2] = .3; vec[3] = 1.; | 
| 950 |  |  | glLightfv(GL_LIGHT0, GL_AMBIENT, vec); | 
| 951 |  |  | glEnable(GL_LIGHT0); | 
| 952 | gwlarson | 3.1 | } | 
| 953 |  |  | /* set up object transform */ | 
| 954 |  |  | if (op->xfac) { | 
| 955 |  |  | if (!normalizing && op->xfb.f.sca < 1.-FTINY | | 
| 956 |  |  | op->xfb.f.sca > 1.+FTINY) | 
| 957 |  |  | glEnable(GL_NORMALIZE); | 
| 958 |  |  | glMatrixMode(GL_MODELVIEW); | 
| 959 |  |  | glPushMatrix(); | 
| 960 |  |  | /* matrix order works out to same */ | 
| 961 |  |  | #ifdef SMLFLT | 
| 962 |  |  | glMultMatrixf((GLfloat *)op->xfb.f.xfm); | 
| 963 |  |  | #else | 
| 964 |  |  | glMultMatrixd((GLdouble *)op->xfb.f.xfm); | 
| 965 |  |  | #endif | 
| 966 |  |  | } | 
| 967 |  |  | /* render the display list */ | 
| 968 |  |  | glCallList(op->listid); | 
| 969 | gwlarson | 3.7 | nrendered++; | 
| 970 | gwlarson | 3.1 | /* restore matrix */ | 
| 971 |  |  | if (op->xfac) { | 
| 972 |  |  | glMatrixMode(GL_MODELVIEW); | 
| 973 |  |  | glPopMatrix(); | 
| 974 |  |  | if (!normalizing) | 
| 975 |  |  | glDisable(GL_NORMALIZE); | 
| 976 |  |  | } | 
| 977 |  |  | /* restore lighting */ | 
| 978 |  |  | if (op->drawcode == DO_LIGHT && op->ol != NULL) | 
| 979 |  |  | for (i = op->ol->nl; i--; ) | 
| 980 |  |  | glDisable(glightid[i]); | 
| 981 | gwlarson | 3.2 | else | 
| 982 |  |  | glDisable(GL_LIGHT0); | 
| 983 | gwlarson | 3.1 | /* check errors */ | 
| 984 |  |  | } | 
| 985 |  |  | glPopAttrib();                  /* restore rendering params */ | 
| 986 | gwlarson | 3.3 | rgl_checkerr("rendering objects in dobj_render"); | 
| 987 | gwlarson | 3.7 | return(nrendered); | 
| 988 | gwlarson | 3.1 | } |