| 1 | – | /* Copyright (c) 1998 Silicon Graphics, Inc. */ | 
| 2 | – |  | 
| 1 |  | #ifndef lint | 
| 2 | < | static char SCCSid[] = "$SunId$ SGI"; | 
| 2 | > | static const char       RCSid[] = "$Id$"; | 
| 3 |  | #endif | 
| 6 | – |  | 
| 4 |  | /* | 
| 5 | < | * Routines for loading and displaying Radiance objects under OpenGL in rholo. | 
| 5 | > | * Routines for loading and displaying Radiance objects in rholo with GLX. | 
| 6 |  | */ | 
| 7 |  |  | 
| 8 | + | #include <string.h> | 
| 9 | + | #include <ctype.h> | 
| 10 | + |  | 
| 11 |  | #include "radogl.h" | 
| 12 |  | #include "tonemap.h" | 
| 13 |  | #include "rhdisp.h" | 
| 14 |  | #include "rhdriver.h" | 
| 15 |  | #include "rhdobj.h" | 
| 16 | + | #include "rtprocess.h" | 
| 17 |  |  | 
| 18 |  | extern FILE     *sstdout;               /* user standard output */ | 
| 19 |  |  | 
| 20 |  | char    rhdcmd[DO_NCMDS][8] = DO_INIT;  /* user command list */ | 
| 21 |  |  | 
| 22 | < | int     (*dobj_lightsamp)() = NULL;     /* pointer to function to get lights */ | 
| 22 | > | /* pointer to function to get lights */ | 
| 23 | > | void    (*dobj_lightsamp)(COLR clr, FVECT direc, FVECT pos) = NULL; | 
| 24 |  |  | 
| 25 |  | #define AVGREFL         0.5             /* assumed average reflectance */ | 
| 26 |  |  | 
| 27 | < | #define MAXAC           64              /* maximum number of args */ | 
| 27 | > | #define MAXAC           512             /* maximum number of args */ | 
| 28 |  |  | 
| 29 |  | #ifndef MINTHRESH | 
| 30 | < | #define MINTHRESH       7.0             /* source threshold w.r.t. mean */ | 
| 30 | > | #define MINTHRESH       5.0             /* source threshold w.r.t. mean */ | 
| 31 |  | #endif | 
| 32 |  |  | 
| 33 |  | #ifndef NALT | 
| 34 |  | #define NALT            11              /* # sampling altitude angles */ | 
| 35 |  | #endif | 
| 36 |  | #ifndef NAZI | 
| 37 | < | #define NAZI            ((int)(PI/2.*NALT+.5)) | 
| 37 | > | #define NAZI            17 | 
| 38 |  | #endif | 
| 39 |  |  | 
| 40 |  | typedef struct dlights { | 
| 55 |  | struct dobject  *next;          /* next object in list */ | 
| 56 |  | char    name[64];               /* object name */ | 
| 57 |  | FVECT   center;                 /* orig. object center */ | 
| 58 | < | FLOAT   radius;                 /* orig. object radius */ | 
| 58 | > | RREAL   radius;                 /* orig. object radius */ | 
| 59 |  | int     listid;                 /* GL display list identifier */ | 
| 60 | < | int     rtp[3];                 /* associated rtrace process */ | 
| 60 | > | int     nlists;                 /* number of lists allocated */ | 
| 61 | > | SUBPROC rtp;                    /* associated rtrace process */ | 
| 62 |  | DLIGHTS *ol;                    /* object lights */ | 
| 63 |  | FULLXF  xfb;                    /* coordinate transform */ | 
| 64 |  | short   drawcode;               /* drawing code */ | 
| 72 |  | static int      lastxfac;               /* last number of transform args */ | 
| 73 |  | static char     *lastxfav[MAXAC+1];     /* saved transform arguments */ | 
| 74 |  |  | 
| 75 | + | #define getdcent(c,op)  multp3(c,(op)->center,(op)->xfb.f.xfm) | 
| 76 | + | #define getdrad(op)     ((op)->radius*(op)->xfb.f.sca) | 
| 77 | + |  | 
| 78 |  | #define RTARGC  8 | 
| 79 |  | static char     *rtargv[RTARGC+1] = {"rtrace", "-h-", "-w-", "-fdd", | 
| 80 |  | "-x", "1", "-oL"}; | 
| 86 |  |  | 
| 87 |  | #define curname         (curobj==NULL ? (char *)NULL : curobj->name) | 
| 88 |  |  | 
| 89 | + | static DOBJECT *getdobj(char *nm); | 
| 90 | + | static int freedobj(DOBJECT *op); | 
| 91 | + | static int savedxf(DOBJECT *op); | 
| 92 | + | static void ssph_sample(COLR clr, FVECT direc, FVECT pos); | 
| 93 | + | static void ssph_direc(FVECT direc, int alt, int azi); | 
| 94 | + | static int ssph_neigh(int sp[2], int next); | 
| 95 | + | static int ssph_compute(void); | 
| 96 | + | static int getdlights(DOBJECT *op, int force); | 
| 97 | + | static void cmderror(int cn, char *err); | 
| 98 |  |  | 
| 99 | + |  | 
| 100 |  | static DOBJECT * | 
| 101 | < | getdobj(nm)                     /* get object from list by name */ | 
| 102 | < | char    *nm; | 
| 101 | > | getdobj(                        /* get object from list by name */ | 
| 102 | > | char    *nm | 
| 103 | > | ) | 
| 104 |  | { | 
| 105 |  | register DOBJECT        *op; | 
| 106 |  |  | 
| 115 |  | } | 
| 116 |  |  | 
| 117 |  |  | 
| 118 | < | static | 
| 119 | < | freedobj(op)                    /* free resources and memory assoc. with op */ | 
| 120 | < | register DOBJECT        *op; | 
| 118 | > | static int | 
| 119 | > | freedobj(                       /* free resources and memory assoc. with op */ | 
| 120 | > | register DOBJECT        *op | 
| 121 | > | ) | 
| 122 |  | { | 
| 123 |  | int     foundlink = 0; | 
| 124 |  | DOBJECT ohead; | 
| 134 |  | } | 
| 135 |  | dobjects = ohead.next; | 
| 136 |  | if (!foundlink) { | 
| 137 | < | glDeleteLists(op->listid, 1); | 
| 138 | < | close_process(op->rtp); | 
| 137 | > | glDeleteLists(op->listid, op->nlists); | 
| 138 | > | close_process(&(op->rtp)); | 
| 139 |  | } | 
| 140 |  | while (op->xfac) | 
| 141 |  | freestr(op->xfav[--op->xfac]); | 
| 142 | < | free((char *)op); | 
| 142 | > | free((void *)op); | 
| 143 |  | return(1); | 
| 144 |  | } | 
| 145 |  |  | 
| 146 |  |  | 
| 147 | < | static | 
| 148 | < | savedxf(op)                     /* save transform for display object */ | 
| 149 | < | register DOBJECT        *op; | 
| 147 | > | static int | 
| 148 | > | savedxf(                        /* save transform for display object */ | 
| 149 | > | register DOBJECT        *op | 
| 150 | > | ) | 
| 151 |  | { | 
| 152 |  | /* free old */ | 
| 153 |  | while (lastxfac) | 
| 165 |  | } | 
| 166 |  |  | 
| 167 |  |  | 
| 168 | < | static | 
| 169 | < | ssph_sample(clr, direc, pos)    /* add sample to current source sphere */ | 
| 170 | < | COLR    clr; | 
| 171 | < | FVECT   direc, pos; | 
| 168 | > | static void | 
| 169 | > | ssph_sample(    /* add sample to current source sphere */ | 
| 170 | > | COLR    clr, | 
| 171 | > | FVECT   direc, | 
| 172 | > | FVECT   pos | 
| 173 | > | ) | 
| 174 |  | { | 
| 175 |  | COLOR   col; | 
| 176 |  | double  d; | 
| 194 |  | } | 
| 195 |  |  | 
| 196 |  |  | 
| 197 | < | static | 
| 198 | < | ssph_direc(direc, alt, azi)     /* compute sphere sampling direction */ | 
| 199 | < | FVECT   direc; | 
| 200 | < | int     alt, azi; | 
| 197 | > | static void | 
| 198 | > | ssph_direc(     /* compute sphere sampling direction */ | 
| 199 | > | FVECT   direc, | 
| 200 | > | int     alt, | 
| 201 | > | int     azi | 
| 202 | > | ) | 
| 203 |  | { | 
| 204 |  | double  phi, d; | 
| 205 |  |  | 
| 212 |  |  | 
| 213 |  |  | 
| 214 |  | static int | 
| 215 | < | ssph_neigh(sp, next)            /* neighbor counter on sphere */ | 
| 216 | < | register int    sp[2]; | 
| 217 | < | int     next; | 
| 215 | > | ssph_neigh(             /* neighbor counter on sphere */ | 
| 216 | > | register int    sp[2], | 
| 217 | > | int     next | 
| 218 | > | ) | 
| 219 |  | { | 
| 220 |  | static short    nneigh = 0;             /* neighbor count */ | 
| 221 |  | static short    neighlist[NAZI+6][2];   /* neighbor list (0 is home) */ | 
| 228 |  | sp[1] = neighlist[nneigh][1]; | 
| 229 |  | return(1); | 
| 230 |  | } | 
| 231 | < | if (sp[0] < 0 | sp[0] >= NALT | sp[1] < 0 | sp[1] >= NAZI) | 
| 231 | > | if ((sp[0] < 0) | (sp[0] >= NALT) | (sp[1] < 0) | (sp[1] >= NAZI)) | 
| 232 |  | return(nneigh=0); | 
| 233 |  | neighlist[0][0] = sp[0]; neighlist[0][1] = sp[1]; | 
| 234 |  | nneigh = 1; | 
| 278 |  | } | 
| 279 |  |  | 
| 280 |  |  | 
| 281 | < | static | 
| 282 | < | ssph_compute()                  /* compute source set from sphere samples */ | 
| 281 | > | static int | 
| 282 | > | ssph_compute(void)                      /* compute source set from sphere samples */ | 
| 283 |  | { | 
| 284 |  | int     ncells, nsamps; | 
| 285 |  | COLOR   csum; | 
| 302 |  | nsamps += ssamp[alt][azi].nsamp; | 
| 303 |  | ncells++; | 
| 304 |  | } | 
| 305 | < | if (dlightsets == NULL | ncells < NALT*NAZI/4) { | 
| 306 | < | bzero((char *)ssamp, sizeof(ssamp)); | 
| 307 | < | return(0); | 
| 305 | > | if ((dlightsets == NULL) | (ncells < NALT*NAZI/4)) { | 
| 306 | > | ncells = 0; | 
| 307 | > | goto done; | 
| 308 |  | } | 
| 309 |  | /* harmonic mean distance */ | 
| 310 |  | if (dlightsets->ravg > FTINY) | 
| 313 |  | dlightsets->ravg = FHUGE; | 
| 314 |  | /* light source threshold */ | 
| 315 |  | thresh = MINTHRESH*bright(csum)/ncells; | 
| 316 | + | if (thresh <= FTINY) { | 
| 317 | + | ncells = 0; | 
| 318 | + | goto done; | 
| 319 | + | } | 
| 320 |  | /* avg. reflected brightness */ | 
| 321 |  | d = AVGREFL / (double)ncells; | 
| 322 |  | scalecolor(csum, d); | 
| 323 | < | if (tmCvColors(&dlightsets->larb, TM_NOCHROM, csum, 1) != TM_E_OK) | 
| 324 | < | error(CONSISTENCY, "bad tone mapping in ssph_compute"); | 
| 323 | > | if (tmCvColors(tmGlobal, &dlightsets->larb, | 
| 324 | > | TM_NOCHROM, &csum, 1) != TM_E_OK) | 
| 325 | > | error(CONSISTENCY, "tone mapping problem in ssph_compute"); | 
| 326 |  | /* greedy light source clustering */ | 
| 327 |  | while (dlightsets->nl < MAXLIGHTS) { | 
| 328 |  | maxbr = 0.;                     /* find brightest cell */ | 
| 342 |  | continue;               /* too dim */ | 
| 343 |  | ssph_direc(v, alt, azi);        /* else add it in */ | 
| 344 |  | VSUM(ls->direc, ls->direc, v, d); | 
| 345 | < | ls->omega++; | 
| 345 | > | ls->omega += 1.; | 
| 346 |  | addcolor(ls->val, ssamp[alt][azi].val); | 
| 347 | + | /* remove from list */ | 
| 348 |  | setcolor(ssamp[alt][azi].val, 0., 0., 0.); | 
| 349 | + | ssamp[alt][azi].nsamp = 0; | 
| 350 |  | } | 
| 351 |  | d = 1./ls->omega;                       /* avg. brightness */ | 
| 352 |  | scalecolor(ls->val, d); | 
| 360 |  | addcolor(dlightsets->lamb, ssamp[alt][azi].val); | 
| 361 |  | d = 1.0/ncells; | 
| 362 |  | scalecolor(dlightsets->lamb, d); | 
| 363 | < | /* clear sphere sample array */ | 
| 364 | < | bzero((char *)ssamp, sizeof(ssamp)); | 
| 363 | > | done:                                   /* clear sphere sample array */ | 
| 364 | > | memset((void *)ssamp, '\0', sizeof(ssamp)); | 
| 365 |  | return(ncells); | 
| 366 |  | } | 
| 367 |  |  | 
| 368 |  |  | 
| 369 | < | static | 
| 370 | < | getdlights(op, force)           /* get lights for display object */ | 
| 371 | < | register DOBJECT        *op; | 
| 372 | < | int     force; | 
| 369 | > | static int | 
| 370 | > | getdlights(             /* get lights for display object */ | 
| 371 | > | register DOBJECT        *op, | 
| 372 | > | int     force | 
| 373 | > | ) | 
| 374 |  | { | 
| 375 |  | double  d2, mind2 = FHUGE*FHUGE; | 
| 376 |  | FVECT   ocent; | 
| 381 |  | if (op->drawcode != DO_LIGHT) | 
| 382 |  | return(0); | 
| 383 |  | /* check for usable light set */ | 
| 384 | < | multp3(ocent, op->center, op->xfb.f.xfm); | 
| 384 | > | getdcent(ocent, op); | 
| 385 |  | for (dl = dlightsets; dl != NULL; dl = dl->next) | 
| 386 |  | if ((d2 = dist2(dl->lcent, ocent)) < mind2) { | 
| 387 |  | op->ol = dl; | 
| 388 |  | mind2 = d2; | 
| 389 |  | } | 
| 390 |  | /* the following is heuristic */ | 
| 391 | < | d2 = 2.*op->radius*op->xfb.f.sca; d2 *= d2; | 
| 391 | > | d2 = 2.*getdrad(op); d2 *= d2; | 
| 392 |  | if ((dl = op->ol) != NULL && (mind2 < 0.0625*dl->ravg*dl->ravg || | 
| 393 | < | mind2 < 4.*op->radius*op->xfb.f.sca*op->radius*op->xfb.f.sca)) | 
| 393 | > | mind2 < 4.*getdrad(op)*getdrad(op))) | 
| 394 |  | return(1); | 
| 395 |  | if (!force) | 
| 396 |  | return(0); | 
| 397 |  | /* need to compute new light set */ | 
| 398 | < | copystruct(&cvw, &stdview); | 
| 398 | > | cvw = stdview; | 
| 399 |  | cvw.type = VT_PER; | 
| 400 |  | VCOPY(cvw.vp, ocent); | 
| 401 |  | cvw.vup[0] = 1.; cvw.vup[1] = cvw.vup[2] = 0.; | 
| 429 |  | quit(0); | 
| 430 |  | if (!ssph_compute()) {          /* compute light sources from sphere */ | 
| 431 |  | dlightsets = dl->next; | 
| 432 | < | free((char *)dl); | 
| 432 | > | free((void *)dl); | 
| 433 |  | return(0); | 
| 434 |  | } | 
| 435 |  | op->ol = dl; | 
| 436 |  | return(1); | 
| 437 |  | memerr: | 
| 438 |  | error(SYSTEM, "out of memory in getdlights"); | 
| 439 | + | return 0; /* pro forma return */ | 
| 440 |  | } | 
| 441 |  |  | 
| 442 |  |  | 
| 443 | < | static int | 
| 444 | < | cmderror(cn, err)               /* report command error */ | 
| 445 | < | int     cn; | 
| 446 | < | char    *err; | 
| 443 | > | static void | 
| 444 | > | cmderror(               /* report command error */ | 
| 445 | > | int     cn, | 
| 446 | > | char    *err | 
| 447 | > | ) | 
| 448 |  | { | 
| 449 |  | sprintf(errmsg, "%s: %s", rhdcmd[cn], err); | 
| 450 |  | error(COMMAND, errmsg); | 
| 417 | – | return(cn); | 
| 451 |  | } | 
| 452 |  |  | 
| 453 |  |  | 
| 454 | < | int | 
| 455 | < | dobj_command(cmd, args)         /* run object display command */ | 
| 456 | < | char    *cmd; | 
| 457 | < | register char   *args; | 
| 454 | > | extern int | 
| 455 | > | dobj_command(           /* run object display command */ | 
| 456 | > | char    *cmd, | 
| 457 | > | register char   *args | 
| 458 | > | ) | 
| 459 |  | { | 
| 460 | < | int     cn, na, doxfm; | 
| 460 | > | int     somechange = 0; | 
| 461 | > | int     cn, na; | 
| 462 |  | register int    nn; | 
| 463 |  | char    *alist[MAXAC+1], *nm; | 
| 464 |  | /* find command */ | 
| 485 |  | dobj_load(alist[0], alist[0]); | 
| 486 |  | else if (na == 2) | 
| 487 |  | dobj_load(alist[0], alist[1]); | 
| 488 | < | else | 
| 489 | < | return(cmderror(cn, "need octree [name]")); | 
| 488 | > | else { | 
| 489 | > | cmderror(cn, "need octree [name]"); | 
| 490 | > | return(0); | 
| 491 | > | } | 
| 492 |  | break; | 
| 493 | < | case DO_UNLOAD:                         /* unload an object */ | 
| 493 | > | case DO_UNLOAD:                         /* clear an object */ | 
| 494 |  | if (na > 1) goto toomany; | 
| 495 |  | if (na && alist[0][0] == '*') | 
| 496 | < | dobj_cleanup(); | 
| 496 | > | somechange += dobj_cleanup(); | 
| 497 |  | else | 
| 498 | < | dobj_unload(na ? alist[0] : curname); | 
| 498 | > | somechange += dobj_unload(na ? alist[0] : curname); | 
| 499 |  | break; | 
| 500 |  | case DO_XFORM:                          /* transform object */ | 
| 501 |  | case DO_MOVE: | 
| 504 |  | } else { | 
| 505 |  | nm = curname; nn = 0; | 
| 506 |  | } | 
| 507 | < | if (cn == DO_MOVE && nn >= na) | 
| 508 | < | return(cmderror(cn, "missing transform")); | 
| 509 | < | dobj_xform(nm, cn==DO_MOVE, na-nn, alist+nn); | 
| 507 | > | if (cn == DO_MOVE && nn >= na) { | 
| 508 | > | cmderror(cn, "missing transform"); | 
| 509 | > | return(0); | 
| 510 | > | } | 
| 511 | > | somechange += dobj_xform(nm, cn==DO_MOVE, na-nn, alist+nn); | 
| 512 |  | break; | 
| 513 |  | case DO_UNMOVE:                         /* undo last transform */ | 
| 514 | < | dobj_unmove(); | 
| 514 | > | somechange += dobj_unmove(); | 
| 515 |  | break; | 
| 516 |  | case DO_OBJECT:                         /* print object statistics */ | 
| 517 | < | dobj_putstats(na ? alist[0] : curname, sstdout); | 
| 517 | > | if (dobj_putstats(na ? alist[0] : curname, sstdout)) | 
| 518 | > | if (na && alist[0][0] != '*' && (curobj == NULL || | 
| 519 | > | strcmp(alist[0], curobj->name))) | 
| 520 | > | savedxf(curobj = getdobj(alist[0])); | 
| 521 |  | break; | 
| 522 |  | case DO_DUP:                            /* duplicate object */ | 
| 523 |  | for (nn = 0; nn < na; nn++) | 
| 525 |  | break; | 
| 526 |  | switch (nn) { | 
| 527 |  | case 0: | 
| 528 | < | return(cmderror(cn, "need new object name")); | 
| 528 | > | cmderror(cn, "need new object name"); | 
| 529 | > | return(0); | 
| 530 |  | case 1: | 
| 531 |  | nm = curname; | 
| 532 |  | break; | 
| 539 |  | if (!dobj_dup(nm, alist[nn-1])) | 
| 540 |  | break; | 
| 541 |  | if (na > nn) | 
| 542 | < | dobj_xform(curname, 1, na-nn, alist+nn); | 
| 542 | > | somechange += dobj_xform(curname, 1, na-nn, alist+nn); | 
| 543 |  | else | 
| 544 |  | curobj->drawcode = DO_HIDE; | 
| 545 | + | savedxf(curobj); | 
| 546 |  | break; | 
| 547 |  | case DO_SHOW:                           /* change rendering option */ | 
| 548 |  | case DO_LIGHT: | 
| 549 |  | case DO_HIDE: | 
| 550 |  | if (na > 1) goto toomany; | 
| 551 |  | dobj_lighting(na ? alist[0] : curname, cn); | 
| 552 | + | somechange++; | 
| 553 |  | break; | 
| 554 |  | default: | 
| 555 |  | error(CONSISTENCY, "bad command id in dobj_command"); | 
| 556 |  | } | 
| 557 | < | dev_view(&odev.v);                      /* redraw */ | 
| 513 | < | return(cn); | 
| 557 | > | return(somechange); | 
| 558 |  | toomany: | 
| 559 | < | return(cmderror(cn, "too many arguments")); | 
| 559 | > | cmderror(cn, "too many arguments"); | 
| 560 | > | return(-1); | 
| 561 |  | } | 
| 562 |  |  | 
| 563 |  |  | 
| 564 | < | dobj_load(oct, nam)             /* create/load an octree object */ | 
| 565 | < | char    *oct, *nam; | 
| 564 | > | extern int | 
| 565 | > | dobj_load(              /* create/load an octree object */ | 
| 566 | > | char    *oct, | 
| 567 | > | char    *nam | 
| 568 | > | ) | 
| 569 |  | { | 
| 522 | – | extern char     *getlibpath(), *getpath(); | 
| 570 |  | char    *fpp, fpath[128]; | 
| 571 |  | register DOBJECT        *op; | 
| 572 |  | /* check arguments */ | 
| 578 |  | error(COMMAND, "missing name"); | 
| 579 |  | return(0); | 
| 580 |  | } | 
| 581 | < | if (*nam == '*' | *nam == '-') { | 
| 581 | > | if ((*nam == '*') | (*nam == '-')) { | 
| 582 |  | error(COMMAND, "illegal name"); | 
| 583 |  | return(0); | 
| 584 |  | } | 
| 585 | + | if (getdobj(nam) != NULL) { | 
| 586 | + | error(COMMAND, "name already taken (clear first)"); | 
| 587 | + | return(0); | 
| 588 | + | } | 
| 589 |  | /* get octree path */ | 
| 590 | < | if ((fpp = getpath(oct, getlibpath(), R_OK)) == NULL) { | 
| 590 | > | if ((fpp = getpath(oct, getrlibpath(), R_OK)) == NULL) { | 
| 591 |  | sprintf(errmsg, "cannot find octree \"%s\"", oct); | 
| 592 |  | error(COMMAND, errmsg); | 
| 593 |  | return(0); | 
| 594 |  | } | 
| 595 |  | strcpy(fpath, fpp); | 
| 545 | – | freedobj(getdobj(nam));         /* free previous use of nam */ | 
| 596 |  | op = (DOBJECT *)malloc(sizeof(DOBJECT)); | 
| 597 |  | if (op == NULL) | 
| 598 |  | error(SYSTEM, "out of memory in dobj_load"); | 
| 605 |  | op->xfav[op->xfac=0] = NULL; | 
| 606 |  | /* load octree into display list */ | 
| 607 |  | dolights = 0; | 
| 608 | < | op->listid = rgl_octlist(fpath, op->center, &op->radius); | 
| 608 | > | domats = 1; | 
| 609 | > | op->listid = rgl_octlist(fpath, op->center, &op->radius, &op->nlists); | 
| 610 |  | /* start rtrace */ | 
| 611 |  | rtargv[RTARGC-1] = fpath; | 
| 612 |  | rtargv[RTARGC] = NULL; | 
| 613 | < | open_process(op->rtp, rtargv); | 
| 613 | > | open_process(&(op->rtp), rtargv); | 
| 614 |  | /* insert into main list */ | 
| 615 |  | op->next = dobjects; | 
| 616 |  | curobj = dobjects = op; | 
| 619 |  | } | 
| 620 |  |  | 
| 621 |  |  | 
| 622 | < | dobj_unload(nam)                        /* free the named object */ | 
| 623 | < | char    *nam; | 
| 622 | > | extern int | 
| 623 | > | dobj_unload(                    /* free the named object */ | 
| 624 | > | char    *nam | 
| 625 | > | ) | 
| 626 |  | { | 
| 627 |  | register DOBJECT        *op; | 
| 628 |  |  | 
| 636 |  | } | 
| 637 |  |  | 
| 638 |  |  | 
| 639 | < | dobj_cleanup()                          /* free all resources */ | 
| 639 | > | extern int | 
| 640 | > | dobj_cleanup(void)                              /* free all resources */ | 
| 641 |  | { | 
| 642 |  | register DLIGHTS        *lp; | 
| 643 |  |  | 
| 646 |  | savedxf(curobj = NULL); | 
| 647 |  | while ((lp = dlightsets) != NULL) { | 
| 648 |  | dlightsets = lp->next; | 
| 649 | < | free((char *)lp); | 
| 649 | > | free((void *)lp); | 
| 650 |  | } | 
| 651 |  | return(1); | 
| 652 |  | } | 
| 653 |  |  | 
| 654 |  |  | 
| 655 | < | dobj_xform(nam, add, ac, av)            /* set/add transform for nam */ | 
| 656 | < | char    *nam; | 
| 657 | < | int     add, ac; | 
| 658 | < | char    **av; | 
| 655 | > | extern int | 
| 656 | > | dobj_xform(             /* set/add transform for nam */ | 
| 657 | > | char    *nam, | 
| 658 | > | int     rel, | 
| 659 | > | int     ac, | 
| 660 | > | char    **av | 
| 661 | > | ) | 
| 662 |  | { | 
| 663 |  | register DOBJECT        *op; | 
| 664 | + | FVECT   cent; | 
| 665 | + | double  rad; | 
| 666 | + | char    scoord[16]; | 
| 667 | + | int     i; | 
| 668 |  |  | 
| 669 |  | if ((op = getdobj(nam)) == NULL) { | 
| 670 |  | error(COMMAND, "no object"); | 
| 671 |  | return(0); | 
| 672 |  | } | 
| 673 | < | if (add) add = op->xfac; | 
| 674 | < | if (ac + add > MAXAC) { | 
| 673 | > | if (rel) | 
| 674 | > | rel = op->xfac + 8; | 
| 675 | > | if (ac + rel > MAXAC) { | 
| 676 |  | error(COMMAND, "too many transform arguments"); | 
| 677 |  | return(0); | 
| 678 |  | } | 
| 679 | < | savedxf(curobj = op); | 
| 680 | < | if (!add) | 
| 679 | > | savedxf(curobj = op);           /* remember current transform */ | 
| 680 | > | if (rel && ac == 4 && !strcmp(av[0], "-t")) | 
| 681 | > | rel = -1;                       /* don't move for translate */ | 
| 682 | > | else { | 
| 683 | > | getdcent(cent, op);             /* don't move if near orig. */ | 
| 684 | > | rad = getdrad(op); | 
| 685 | > | if (DOT(cent,cent) < rad*rad) | 
| 686 | > | rel = -1; | 
| 687 | > | } | 
| 688 | > | if (!rel) {                             /* remove old transform */ | 
| 689 |  | while (op->xfac) | 
| 690 |  | freestr(op->xfav[--op->xfac]); | 
| 691 | + | } else if (rel > 0) {                   /* relative move */ | 
| 692 | + | op->xfav[op->xfac++] = savestr("-t"); | 
| 693 | + | for (i = 0; i < 3; i++) { | 
| 694 | + | sprintf(scoord, "%.4e", -cent[i]); | 
| 695 | + | op->xfav[op->xfac++] = savestr(scoord); | 
| 696 | + | } | 
| 697 | + | } | 
| 698 |  | while (ac--) | 
| 699 |  | op->xfav[op->xfac++] = savestr(*av++); | 
| 700 | + | if (rel > 0) {                          /* move back */ | 
| 701 | + | op->xfav[op->xfac++] = savestr("-t"); | 
| 702 | + | for (i = 0; i < 3; i++) { | 
| 703 | + | sprintf(scoord, "%.4e", cent[i]); | 
| 704 | + | op->xfav[op->xfac++] = savestr(scoord); | 
| 705 | + | } | 
| 706 | + | } | 
| 707 |  | op->xfav[op->xfac] = NULL; | 
| 708 |  | if (fullxf(&op->xfb, op->xfac, op->xfav) != op->xfac) { | 
| 709 |  | error(COMMAND, "bad transform arguments"); | 
| 717 |  | } | 
| 718 |  |  | 
| 719 |  |  | 
| 720 | < | dobj_putstats(nam, fp)                  /* put out statistics for nam */ | 
| 721 | < | char    *nam; | 
| 722 | < | FILE    *fp; | 
| 720 | > | extern int | 
| 721 | > | dobj_putstats(                  /* put out statistics for nam */ | 
| 722 | > | char    *nam, | 
| 723 | > | FILE    *fp | 
| 724 | > | ) | 
| 725 |  | { | 
| 726 |  | FVECT   ocent; | 
| 727 |  | register DOBJECT        *op; | 
| 741 |  | error(COMMAND, "unknown object"); | 
| 742 |  | return(0); | 
| 743 |  | } | 
| 744 | < | multp3(ocent, op->center, op->xfb.f.xfm); | 
| 745 | < | fprintf(fp, "%s: %s, center [%f %f %f], radius %f", op->name, | 
| 746 | < | op->drawcode==DO_HIDE ? "hid" : | 
| 747 | < | op->drawcode==DO_LIGHT && op->ol!=NULL ? "lit" : | 
| 744 | > | getdcent(ocent, op); | 
| 745 | > | fprintf(fp, "%s: %s, center [%g %g %g], radius %g", op->name, | 
| 746 | > | op->drawcode==DO_HIDE ? "hidden" : | 
| 747 | > | op->drawcode==DO_LIGHT && op->ol!=NULL ? "lighted" : | 
| 748 |  | "shown", | 
| 749 | < | ocent[0],ocent[1],ocent[2], op->radius*op->xfb.f.sca); | 
| 749 | > | ocent[0],ocent[1],ocent[2], getdrad(op)); | 
| 750 |  | if (op->xfac) | 
| 751 |  | fputs(", (xform", fp); | 
| 752 |  | for (i = 0; i < op->xfac; i++) { | 
| 760 |  | } | 
| 761 |  |  | 
| 762 |  |  | 
| 763 | < | dobj_unmove()                           /* undo last transform change */ | 
| 763 | > | extern int | 
| 764 | > | dobj_unmove(void)                               /* undo last transform change */ | 
| 765 |  | { | 
| 766 |  | int     txfac; | 
| 767 |  | char    *txfav[MAXAC+1]; | 
| 771 |  | return(0); | 
| 772 |  | } | 
| 773 |  | /* hold last transform */ | 
| 774 | < | bcopy((char *)lastxfav, (char *)txfav, | 
| 774 | > | memcpy((void *)txfav, (void *)lastxfav, | 
| 775 |  | (txfac=lastxfac)*sizeof(char *)); | 
| 776 |  | /* save this transform */ | 
| 777 | < | bcopy((char *)curobj->xfav, (char *)lastxfav, | 
| 777 | > | memcpy((void *)lastxfav, (void *)curobj->xfav, | 
| 778 |  | (lastxfac=curobj->xfac)*sizeof(char *)); | 
| 779 |  | /* copy back last transform */ | 
| 780 | < | bcopy((char *)txfav, (char *)curobj->xfav, | 
| 780 | > | memcpy((void *)curobj->xfav, (void *)txfav, | 
| 781 |  | (curobj->xfac=txfac)*sizeof(char *)); | 
| 782 |  | /* set matrices */ | 
| 783 |  | fullxf(&curobj->xfb, curobj->xfac, curobj->xfav); | 
| 787 |  | } | 
| 788 |  |  | 
| 789 |  |  | 
| 790 | < | dobj_dup(oldnm, nam)                    /* duplicate object oldnm as nam */ | 
| 791 | < | char    *oldnm, *nam; | 
| 790 | > | extern int | 
| 791 | > | dobj_dup(                       /* duplicate object oldnm as nam */ | 
| 792 | > | char    *oldnm, | 
| 793 | > | char    *nam | 
| 794 | > | ) | 
| 795 |  | { | 
| 796 |  | register DOBJECT        *op, *opdup; | 
| 797 |  | /* check arguments */ | 
| 803 |  | error(COMMAND, "missing name"); | 
| 804 |  | return(0); | 
| 805 |  | } | 
| 806 | < | if (*nam == '*' | *nam == '-') { | 
| 806 | > | if ((*nam == '*') | (*nam == '-')) { | 
| 807 |  | error(COMMAND, "illegal name"); | 
| 808 |  | return(0); | 
| 809 |  | } | 
| 810 | + | if (getdobj(nam) != NULL) { | 
| 811 | + | error(COMMAND, "name already taken (clear first)"); | 
| 812 | + | return(0); | 
| 813 | + | } | 
| 814 |  | /* allocate and copy struct */ | 
| 815 |  | opdup = (DOBJECT *)malloc(sizeof(DOBJECT)); | 
| 816 |  | if (opdup == NULL) | 
| 817 |  | error(SYSTEM, "out of memory in dobj_dup"); | 
| 818 | < | copystruct(opdup, op); | 
| 818 | > | *opdup = *op; | 
| 819 |  | /* rename */ | 
| 820 |  | strcpy(opdup->name, nam); | 
| 821 |  | /* get our own copy of transform */ | 
| 829 |  | } | 
| 830 |  |  | 
| 831 |  |  | 
| 832 | < | dobj_lighting(nam, cn)          /* set up lighting for display object */ | 
| 833 | < | char    *nam; | 
| 834 | < | int     cn; | 
| 832 | > | extern int | 
| 833 | > | dobj_lighting(          /* set up lighting for display object */ | 
| 834 | > | char    *nam, | 
| 835 | > | int     cn | 
| 836 | > | ) | 
| 837 |  | { | 
| 838 |  | int     i, res[2]; | 
| 839 |  | VIEW    *dv; | 
| 852 |  | } else if ((op = getdobj(nam)) == NULL) { | 
| 853 |  | error(COMMAND, "unknown object"); | 
| 854 |  | return(0); | 
| 855 | < | } else if ((op->drawcode = cn) == DO_LIGHT) | 
| 856 | < | getdlights(op, 1); | 
| 857 | < | else | 
| 855 | > | } else if ((op->drawcode = cn) == DO_LIGHT) { | 
| 856 | > | if (!getdlights(op, 1)) | 
| 857 | > | error(COMMAND, "insufficient samples to light object"); | 
| 858 | > | } else | 
| 859 |  | op->ol = NULL; | 
| 860 |  |  | 
| 861 |  | if (dobj_lightsamp != NULL) {           /* restore beam set */ | 
| 865 |  | beam_view(dv, res[0], res[1]); | 
| 866 |  | beam_sync(1);                   /* update server */ | 
| 867 |  | } | 
| 868 | + | return 0; /* XXX not sure if this is the right value */ | 
| 869 |  | } | 
| 870 |  |  | 
| 871 |  |  | 
| 872 | < | double | 
| 873 | < | dobj_trace(rorg, rdir)          /* check for ray intersection with objects */ | 
| 874 | < | FVECT   rorg, rdir; | 
| 872 | > | extern double | 
| 873 | > | dobj_trace(     /* check for ray intersection with object(s) */ | 
| 874 | > | char    nm[], | 
| 875 | > | FVECT  rorg, | 
| 876 | > | FVECT  rdir | 
| 877 | > | ) | 
| 878 |  | { | 
| 879 |  | register DOBJECT        *op; | 
| 880 |  | FVECT   xorg, xdir; | 
| 881 | < | double  darr[6], mindist = FHUGE; | 
| 882 | < | /* check each visible object */ | 
| 883 | < | for (op = dobjects; op != NULL; op = op->next) { | 
| 884 | < | if (op->drawcode == DO_HIDE) | 
| 885 | < | continue; | 
| 886 | < | if (op->xfac) {         /* transform ray */ | 
| 887 | < | multp3(xorg, rorg, op->xfb.b.xfm); | 
| 888 | < | multv3(xdir, rdir, op->xfb.b.xfm); | 
| 889 | < | VCOPY(darr, xorg); VCOPY(darr+3, xdir); | 
| 890 | < | } else { | 
| 891 | < | VCOPY(darr, rorg); VCOPY(darr+3, rdir); | 
| 881 | > | double  darr[6]; | 
| 882 | > | /* check each visible object? */ | 
| 883 | > | if (nm == NULL || *nm == '*') { | 
| 884 | > | double  dist, mindist = 1.01*FHUGE; | 
| 885 | > |  | 
| 886 | > | if (nm != NULL) nm[0] = '\0'; | 
| 887 | > | for (op = dobjects; op != NULL; op = op->next) { | 
| 888 | > | if (op->drawcode == DO_HIDE) | 
| 889 | > | continue; | 
| 890 | > | dist = dobj_trace(op->name, rorg, rdir); | 
| 891 | > | if (dist < mindist) { | 
| 892 | > | if (nm != NULL) strcpy(nm, op->name); | 
| 893 | > | mindist = dist; | 
| 894 | > | } | 
| 895 |  | } | 
| 896 | < | /* trace it */ | 
| 793 | < | if (process(op->rtp, darr, darr, sizeof(double), | 
| 794 | < | 6*sizeof(double)) != sizeof(double)) | 
| 795 | < | error(SYSTEM, "rtrace communication error"); | 
| 796 | < | /* get closest */ | 
| 797 | < | if ((darr[0] *= op->xfb.f.sca) < mindist) | 
| 798 | < | mindist = darr[0]; | 
| 896 | > | return(mindist); | 
| 897 |  | } | 
| 898 | < | return(mindist); | 
| 898 | > | /* else check particular object */ | 
| 899 | > | if ((op = getdobj(nm)) == NULL) { | 
| 900 | > | error(COMMAND, "unknown object"); | 
| 901 | > | return(FHUGE); | 
| 902 | > | } | 
| 903 | > | if (op->xfac) {         /* put ray in local coordinates */ | 
| 904 | > | multp3(xorg, rorg, op->xfb.b.xfm); | 
| 905 | > | multv3(xdir, rdir, op->xfb.b.xfm); | 
| 906 | > | VCOPY(darr, xorg); VCOPY(darr+3, xdir); | 
| 907 | > | } else { | 
| 908 | > | VCOPY(darr, rorg); VCOPY(darr+3, rdir); | 
| 909 | > | } | 
| 910 | > | /* trace it */ | 
| 911 | > | if (process(&(op->rtp), (char *)darr, (char *)darr, sizeof(double), | 
| 912 | > | 6*sizeof(double)) != sizeof(double)) | 
| 913 | > | error(SYSTEM, "rtrace communication error"); | 
| 914 | > | /* return distance */ | 
| 915 | > | if (darr[0] >= .99*FHUGE) | 
| 916 | > | return(FHUGE); | 
| 917 | > | return(darr[0]*op->xfb.f.sca); | 
| 918 |  | } | 
| 919 |  |  | 
| 920 |  |  | 
| 921 | < | dobj_render()                   /* render our objects in OpenGL */ | 
| 921 | > | extern int | 
| 922 | > | dobj_render(void)                       /* render our objects in OpenGL */ | 
| 923 |  | { | 
| 924 | + | int     nrendered = 0; | 
| 925 |  | GLboolean       normalizing; | 
| 926 |  | GLfloat vec[4]; | 
| 927 | + | FVECT   v1; | 
| 928 |  | register DOBJECT        *op; | 
| 929 |  | register int    i; | 
| 930 |  | /* anything to render? */ | 
| 932 |  | if (op->drawcode != DO_HIDE) | 
| 933 |  | break; | 
| 934 |  | if (op == NULL) | 
| 935 | < | return(1); | 
| 935 | > | return(0); | 
| 936 |  | /* set up general rendering params */ | 
| 937 |  | glGetBooleanv(GL_NORMALIZE, &normalizing); | 
| 938 | < | glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT| | 
| 939 | < | GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT); | 
| 938 | > | glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT|GL_ENABLE_BIT| | 
| 939 | > | GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT); | 
| 940 |  | glDepthFunc(GL_LESS); | 
| 941 |  | glEnable(GL_DEPTH_TEST); | 
| 942 |  | glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); | 
| 954 |  | continue; | 
| 955 |  | /* set up lighting */ | 
| 956 |  | if (op->drawcode == DO_LIGHT && op->ol != NULL) { | 
| 957 | < | BYTE    pval; | 
| 957 | > | uby8    pval; | 
| 958 |  | double  expval, d; | 
| 959 | < |  | 
| 960 | < | if (tmMapPixels(&pval, &op->ol->larb, TM_NOCHROM, 1) | 
| 961 | < | != TM_E_OK) | 
| 959 | > | /* use computed sources */ | 
| 960 | > | if (tmMapPixels(tmGlobal, &pval, &op->ol->larb, | 
| 961 | > | TM_NOCHROM, 1) != TM_E_OK) | 
| 962 |  | error(CONSISTENCY, "dobj_render w/o tone map"); | 
| 963 |  | expval = pval * (WHTEFFICACY/256.) / | 
| 964 |  | tmLuminance(op->ol->larb); | 
| 982 |  | glLightfv(glightid[i], GL_AMBIENT, vec); | 
| 983 |  | glEnable(glightid[i]); | 
| 984 |  | } | 
| 985 | < | } else { | 
| 986 | < | vec[0] = vec[1] = vec[2] = 1.; vec[3] = 1.; | 
| 985 | > | } else {                        /* fake lighting */ | 
| 986 | > | vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.; | 
| 987 |  | glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec); | 
| 988 | + | getdcent(v1, op); | 
| 989 | + | VSUB(v1, odev.v.vp, v1); | 
| 990 | + | if (normalize(v1) <= getdrad(op)) { | 
| 991 | + | vec[0] = -odev.v.vdir[0]; | 
| 992 | + | vec[1] = -odev.v.vdir[1]; | 
| 993 | + | vec[2] = -odev.v.vdir[2]; | 
| 994 | + | } else | 
| 995 | + | VCOPY(vec, v1); | 
| 996 | + | vec[3] = 0.; | 
| 997 | + | glLightfv(GL_LIGHT0, GL_POSITION, vec); | 
| 998 | + | vec[0] = vec[1] = vec[2] = .7; vec[3] = 1.; | 
| 999 | + | glLightfv(GL_LIGHT0, GL_SPECULAR, vec); | 
| 1000 | + | glLightfv(GL_LIGHT0, GL_DIFFUSE, vec); | 
| 1001 | + | vec[0] = vec[1] = vec[2] = .3; vec[3] = 1.; | 
| 1002 | + | glLightfv(GL_LIGHT0, GL_AMBIENT, vec); | 
| 1003 | + | glEnable(GL_LIGHT0); | 
| 1004 |  | } | 
| 1005 |  | /* set up object transform */ | 
| 1006 |  | if (op->xfac) { | 
| 1007 | < | if (!normalizing && op->xfb.f.sca < 1.-FTINY | | 
| 1008 | < | op->xfb.f.sca > 1.+FTINY) | 
| 1007 | > | if (!normalizing && (op->xfb.f.sca < 1.-FTINY) | | 
| 1008 | > | (op->xfb.f.sca > 1.+FTINY)) | 
| 1009 |  | glEnable(GL_NORMALIZE); | 
| 1010 |  | glMatrixMode(GL_MODELVIEW); | 
| 1011 |  | glPushMatrix(); | 
| 1018 |  | } | 
| 1019 |  | /* render the display list */ | 
| 1020 |  | glCallList(op->listid); | 
| 1021 | + | nrendered++; | 
| 1022 |  | /* restore matrix */ | 
| 1023 |  | if (op->xfac) { | 
| 1024 |  | glMatrixMode(GL_MODELVIEW); | 
| 1030 |  | if (op->drawcode == DO_LIGHT && op->ol != NULL) | 
| 1031 |  | for (i = op->ol->nl; i--; ) | 
| 1032 |  | glDisable(glightid[i]); | 
| 1033 | + | else | 
| 1034 | + | glDisable(GL_LIGHT0); | 
| 1035 |  | /* check errors */ | 
| 897 | – | rgl_checkerr("rendering object in dobj_render"); | 
| 1036 |  | } | 
| 1037 |  | glPopAttrib();                  /* restore rendering params */ | 
| 1038 | < | return(1); | 
| 1038 | > | rgl_checkerr("rendering objects in dobj_render"); | 
| 1039 | > | return(nrendered); | 
| 1040 |  | } |