Back to index

radiance  4R0+20100331
rhdobj.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rhdobj.c,v 3.18 2005/01/07 20:33:02 greg Exp $";
00003 #endif
00004 /*
00005  * Routines for loading and displaying Radiance objects in rholo with GLX.
00006  */
00007 
00008 #include <string.h>
00009 #include <ctype.h>
00010 
00011 #include "radogl.h"
00012 #include "tonemap.h"
00013 #include "rhdisp.h"
00014 #include "rhdriver.h"
00015 #include "rhdobj.h"
00016 #include "rtprocess.h"
00017 
00018 extern FILE   *sstdout;            /* user standard output */
00019 
00020 char   rhdcmd[DO_NCMDS][8] = DO_INIT;     /* user command list */
00021 
00022 /* pointer to function to get lights */
00023 void   (*dobj_lightsamp)(COLR clr, FVECT direc, FVECT pos) = NULL;
00024 
00025 #define       AVGREFL              0.5           /* assumed average reflectance */
00026 
00027 #define       MAXAC         512           /* maximum number of args */
00028 
00029 #ifndef MINTHRESH
00030 #define MINTHRESH    5.0           /* source threshold w.r.t. mean */
00031 #endif
00032 
00033 #ifndef NALT
00034 #define NALT         11            /* # sampling altitude angles */
00035 #endif
00036 #ifndef NAZI
00037 #define NAZI         ((int)(PI/2.*NALT+.5))
00038 #endif
00039 
00040 typedef struct dlights {
00041        struct dlights       *next;        /* next in lighting set list */
00042        FVECT  lcent;               /* computed lighting center */
00043        double ravg;                /* harmonic mean free range radius */
00044        TMbright      larb;         /* average reflected brightness */
00045        COLOR  lamb;                /* local ambient value */
00046        short  nl;                  /* number of lights in this set */
00047        struct lsource {
00048               FVECT  direc;               /* source direction */
00049               double omega;               /* source solid angle */
00050               COLOR  val;                 /* source color */
00051        } li[MAXLIGHTS];            /* light sources */
00052 } DLIGHTS;                  /* a light source set */
00053 
00054 typedef struct dobject {
00055        struct dobject       *next;        /* next object in list */
00056        char   name[64];            /* object name */
00057        FVECT  center;                     /* orig. object center */
00058        RREAL  radius;                     /* orig. object radius */
00059        int    listid;                     /* GL display list identifier */
00060        int    nlists;                     /* number of lists allocated */
00061        SUBPROC       rtp;                 /* associated rtrace process */
00062        DLIGHTS       *ol;                 /* object lights */
00063        FULLXF xfb;                 /* coordinate transform */
00064        short  drawcode;            /* drawing code */
00065        short  xfac;                /* transform argument count */
00066        char   *xfav[MAXAC+1];             /* transform args */
00067 } DOBJECT;                  /* a displayable object */
00068 
00069 static DLIGHTS       *dlightsets;         /* lighting sets */
00070 static DOBJECT       *dobjects;           /* display object list */
00071 static DOBJECT       *curobj;             /* current (last referred) object */
00072 static int    lastxfac;            /* last number of transform args */
00073 static char   *lastxfav[MAXAC+1];  /* saved transform arguments */
00074 
00075 #define getdcent(c,op)      multp3(c,(op)->center,(op)->xfb.f.xfm)
00076 #define getdrad(op)  ((op)->radius*(op)->xfb.f.sca)
00077 
00078 #define       RTARGC 8
00079 static char   *rtargv[RTARGC+1] = {"rtrace", "-h-", "-w-", "-fdd",
00080                                    "-x", "1", "-oL"};
00081 
00082 static struct {
00083        int    nsamp;               /* number of ray samples */
00084        COLOR  val;                 /* value (sum) */
00085 } ssamp[NALT][NAZI];        /* current sphere samples */
00086 
00087 #define       curname              (curobj==NULL ? (char *)NULL : curobj->name)
00088 
00089 static DOBJECT *getdobj(char *nm);
00090 static int freedobj(DOBJECT *op);
00091 static int savedxf(DOBJECT *op);
00092 static void ssph_sample(COLR clr, FVECT direc, FVECT pos);
00093 static void ssph_direc(FVECT direc, int alt, int azi);
00094 static int ssph_neigh(int sp[2], int next);
00095 static int ssph_compute(void);
00096 static int getdlights(DOBJECT *op, int force);
00097 static void cmderror(int cn, char *err);
00098 
00099 
00100 static DOBJECT *
00101 getdobj(                    /* get object from list by name */
00102        char   *nm
00103 )
00104 {
00105        register DOBJECT     *op;
00106 
00107        if (nm == NULL)
00108               return(NULL);
00109        if (nm == curname)
00110               return(curobj);
00111        for (op = dobjects; op != NULL; op = op->next)
00112               if (!strcmp(op->name, nm))
00113                      break;
00114        return(op);
00115 }
00116 
00117 
00118 static int
00119 freedobj(                   /* free resources and memory assoc. with op */
00120        register DOBJECT     *op
00121 )
00122 {
00123        int    foundlink = 0;
00124        DOBJECT       ohead;
00125        register DOBJECT     *opl;
00126 
00127        if (op == NULL)
00128               return(0);
00129        ohead.next = dobjects;
00130        for (opl = &ohead; opl->next != NULL; opl = opl->next) {
00131               if (opl->next == op && (opl->next = op->next) == NULL)
00132                      break;
00133               foundlink += opl->next->listid == op->listid;
00134        }
00135        dobjects = ohead.next;
00136        if (!foundlink) {
00137               glDeleteLists(op->listid, op->nlists);
00138               close_process(&(op->rtp));
00139        }
00140        while (op->xfac)
00141               freestr(op->xfav[--op->xfac]);
00142        free((void *)op);
00143        return(1);
00144 }
00145 
00146 
00147 static int
00148 savedxf(                    /* save transform for display object */
00149        register DOBJECT     *op
00150 )
00151 {
00152                                    /* free old */
00153        while (lastxfac)
00154               freestr(lastxfav[--lastxfac]);
00155                                    /* nothing to save? */
00156        if (op == NULL) {
00157               lastxfav[0] = NULL;
00158               return(0);
00159        }
00160                                    /* else save new */
00161        for (lastxfac = 0; lastxfac < op->xfac; lastxfac++)
00162               lastxfav[lastxfac] = savestr(op->xfav[lastxfac]);
00163        lastxfav[lastxfac] = NULL;
00164        return(1);
00165 }
00166 
00167 
00168 static void
00169 ssph_sample(  /* add sample to current source sphere */
00170        COLR   clr,
00171        FVECT  direc,
00172        FVECT  pos
00173 )
00174 {
00175        COLOR  col;
00176        double d;
00177        register int  alt, azi;
00178 
00179        if (dlightsets == NULL)
00180               return;
00181        if (pos == NULL)
00182               d = FHUGE;           /* sample is at infinity */
00183        else if ((d = (pos[0] - dlightsets->lcent[0])*direc[0] +
00184                      (pos[1] - dlightsets->lcent[1])*direc[1] +
00185                      (pos[2] - dlightsets->lcent[2])*direc[2]) > FTINY)
00186               dlightsets->ravg += 1./d;
00187        else
00188               return;                     /* sample is behind us */
00189        alt = NALT*(1.-FTINY)*(.5*(1.+FTINY) + direc[2]*.5);
00190        azi = NAZI*(1.-FTINY)*(.5*(1.+FTINY) + .5/PI*atan2(direc[1],direc[0]));
00191        colr_color(col, clr);
00192        addcolor(ssamp[alt][azi].val, col);
00193        ssamp[alt][azi].nsamp++;
00194 }
00195 
00196 
00197 static void
00198 ssph_direc(   /* compute sphere sampling direction */
00199        FVECT  direc,
00200        int    alt,
00201        int    azi
00202 )
00203 {
00204        double phi, d;
00205 
00206        direc[2] = 2./NALT*(alt+.5) - 1.;
00207        d = sqrt(1. - direc[2]*direc[2]);
00208        phi = 2.*PI/NAZI*(azi+.5) - PI;
00209        direc[0] = d*cos(phi);
00210        direc[1] = d*sin(phi);
00211 }
00212 
00213 
00214 static int
00215 ssph_neigh(          /* neighbor counter on sphere */
00216        register int  sp[2],
00217        int    next
00218 )
00219 {
00220        static short  nneigh = 0;          /* neighbor count */
00221        static short  neighlist[NAZI+6][2];       /* neighbor list (0 is home) */
00222        register int  i;
00223 
00224        if (next) {
00225               if (nneigh <= 0)
00226                      return(0);
00227               sp[0] = neighlist[--nneigh][0];
00228               sp[1] = neighlist[nneigh][1];
00229               return(1);
00230        }
00231        if ((sp[0] < 0) | (sp[0] >= NALT) | (sp[1] < 0) | (sp[1] >= NAZI))
00232               return(nneigh=0);
00233        neighlist[0][0] = sp[0]; neighlist[0][1] = sp[1];
00234        nneigh = 1;
00235        if (sp[0] == 0) {
00236               neighlist[nneigh][0] = 1;
00237               neighlist[nneigh++][1] = (sp[1]+1)%NAZI;
00238               neighlist[nneigh][0] = 1;
00239               neighlist[nneigh++][1] = sp[1];
00240               neighlist[nneigh][0] = 1;
00241               neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI;
00242               for (i = 0; i < NAZI; i++)
00243                      if (i != sp[1]) {
00244                             neighlist[nneigh][0] = 0;
00245                             neighlist[nneigh++][1] = i;
00246                      }
00247        } else if (sp[0] == NALT-1) {
00248               neighlist[nneigh][0] = NALT-2;
00249               neighlist[nneigh++][1] = (sp[1]+1)%NAZI;
00250               neighlist[nneigh][0] = NALT-2;
00251               neighlist[nneigh++][1] = sp[1];
00252               neighlist[nneigh][0] = NALT-2;
00253               neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI;
00254               for (i = 0; i < NAZI; i++)
00255                      if (i != sp[1]) {
00256                             neighlist[nneigh][0] = NALT-1;
00257                             neighlist[nneigh++][1] = i;
00258                      }
00259        } else {
00260               neighlist[nneigh][0] = sp[0]-1;
00261               neighlist[nneigh++][1] = (sp[1]+1)%NAZI;
00262               neighlist[nneigh][0] = sp[0]-1;
00263               neighlist[nneigh++][1] = sp[1];
00264               neighlist[nneigh][0] = sp[0]-1;
00265               neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI;
00266               neighlist[nneigh][0] = sp[0];
00267               neighlist[nneigh++][1] = (sp[1]+1)%NAZI;
00268               neighlist[nneigh][0] = sp[0];
00269               neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI;
00270               neighlist[nneigh][0] = sp[0]+1;
00271               neighlist[nneigh++][1] = (sp[1]+1)%NAZI;
00272               neighlist[nneigh][0] = sp[0]+1;
00273               neighlist[nneigh++][1] = sp[1];
00274               neighlist[nneigh][0] = sp[0]+1;
00275               neighlist[nneigh++][1] = (sp[1]+(NAZI-1))%NAZI;
00276        }
00277        return(nneigh);
00278 }
00279 
00280 
00281 static int
00282 ssph_compute(void)                 /* compute source set from sphere samples */
00283 {
00284        int    ncells, nsamps;
00285        COLOR  csum;
00286        FVECT  v;
00287        double d, thresh, maxbr;
00288        int    maxalt, maxazi, spos[2];
00289        register int  alt, azi;
00290        register struct lsource     *ls;
00291                                    /* count & average sampled cells */
00292        setcolor(csum, 0., 0., 0.);
00293        ncells = nsamps = 0;
00294        for (alt = 0; alt < NALT; alt++)
00295               for (azi = 0; azi < NAZI; azi++)
00296                      if (ssamp[alt][azi].nsamp) {
00297                             if (ssamp[alt][azi].nsamp > 1) {
00298                                    d = 1.0/ssamp[alt][azi].nsamp;
00299                                    scalecolor(ssamp[alt][azi].val, d);
00300                             }
00301                             addcolor(csum, ssamp[alt][azi].val);
00302                             nsamps += ssamp[alt][azi].nsamp;
00303                             ncells++;
00304                      }
00305        if ((dlightsets == NULL) | (ncells < NALT*NAZI/4)) {
00306               ncells = 0;
00307               goto done;
00308        }
00309                                           /* harmonic mean distance */
00310        if (dlightsets->ravg > FTINY)
00311               dlightsets->ravg = nsamps / dlightsets->ravg;
00312        else
00313               dlightsets->ravg = FHUGE;
00314                                           /* light source threshold */
00315        thresh = MINTHRESH*bright(csum)/ncells;
00316        if (thresh <= FTINY) {
00317               ncells = 0;
00318               goto done;
00319        }
00320                                           /* avg. reflected brightness */
00321        d = AVGREFL / (double)ncells;      
00322        scalecolor(csum, d);
00323        if (tmCvColors(tmGlobal, &dlightsets->larb,
00324                      TM_NOCHROM, &csum, 1) != TM_E_OK)
00325               error(CONSISTENCY, "tone mapping problem in ssph_compute");
00326                                    /* greedy light source clustering */
00327        while (dlightsets->nl < MAXLIGHTS) {
00328               maxbr = 0.;                 /* find brightest cell */
00329               for (alt = 0; alt < NALT; alt++)
00330                      for (azi = 0; azi < NAZI; azi++)
00331                             if ((d = bright(ssamp[alt][azi].val)) > maxbr) {
00332                                    maxalt = alt; maxazi = azi;
00333                                    maxbr = d;
00334                             }
00335               if (maxbr < thresh)         /* below threshold? */
00336                      break;
00337               ls = dlightsets->li + dlightsets->nl++;
00338               spos[0] = maxalt; spos[1] = maxazi;       /* cluster */
00339               for (ssph_neigh(spos, 0); ssph_neigh(spos, 1); ) {
00340                      alt = spos[0]; azi = spos[1];
00341                      if ((d = bright(ssamp[alt][azi].val)) < .75*thresh)
00342                             continue;            /* too dim */
00343                      ssph_direc(v, alt, azi);    /* else add it in */
00344                      VSUM(ls->direc, ls->direc, v, d);
00345                      ls->omega += 1.;
00346                      addcolor(ls->val, ssamp[alt][azi].val);
00347                                                  /* remove from list */
00348                      setcolor(ssamp[alt][azi].val, 0., 0., 0.);
00349                      ssamp[alt][azi].nsamp = 0;
00350               }
00351               d = 1./ls->omega;                  /* avg. brightness */
00352               scalecolor(ls->val, d);
00353               ls->omega *= 4.*PI/(NALT*NAZI);           /* solid angle */
00354               normalize(ls->direc);                     /* direction */
00355        }
00356                                    /* compute ambient remainder */
00357        for (alt = 0; alt < NALT; alt++)
00358               for (azi = 0; azi < NAZI; azi++)
00359                      if (ssamp[alt][azi].nsamp)
00360                             addcolor(dlightsets->lamb, ssamp[alt][azi].val);
00361        d = 1.0/ncells;
00362        scalecolor(dlightsets->lamb, d);
00363 done:                              /* clear sphere sample array */
00364        memset((void *)ssamp, '\0', sizeof(ssamp));
00365        return(ncells);
00366 }
00367 
00368 
00369 static int
00370 getdlights(          /* get lights for display object */
00371        register DOBJECT     *op,
00372        int    force
00373 )
00374 {
00375        double d2, mind2 = FHUGE*FHUGE;
00376        FVECT  ocent;
00377        VIEW   cvw;
00378        register DLIGHTS     *dl;
00379 
00380        op->ol = NULL;
00381        if (op->drawcode != DO_LIGHT)
00382               return(0);
00383                                    /* check for usable light set */
00384        getdcent(ocent, op);
00385        for (dl = dlightsets; dl != NULL; dl = dl->next)
00386               if ((d2 = dist2(dl->lcent, ocent)) < mind2) {
00387                      op->ol = dl;
00388                      mind2 = d2;
00389               }
00390                                    /* the following is heuristic */
00391        d2 = 2.*getdrad(op); d2 *= d2;
00392        if ((dl = op->ol) != NULL && (mind2 < 0.0625*dl->ravg*dl->ravg ||
00393                      mind2 < 4.*getdrad(op)*getdrad(op)))
00394               return(1);
00395        if (!force)
00396               return(0);
00397                                    /* need to compute new light set */
00398        cvw = stdview;
00399        cvw.type = VT_PER;
00400        VCOPY(cvw.vp, ocent);
00401        cvw.vup[0] = 1.; cvw.vup[1] = cvw.vup[2] = 0.;
00402        cvw.horiz = 90; cvw.vert = 90.;
00403        beam_init(1);               /* query beams through center */
00404        cvw.vdir[0] = cvw.vdir[1] = 0.; cvw.vdir[2] = 1.;
00405        setview(&cvw); beam_view(&cvw, 0, 0);
00406        cvw.vdir[0] = cvw.vdir[1] = 0.; cvw.vdir[2] = -1.;
00407        setview(&cvw); beam_view(&cvw, 0, 0);
00408        cvw.vup[0] = cvw.vup[1] = 0.; cvw.vup[2] = 1.;
00409        cvw.vdir[0] = cvw.vdir[2] = 0.; cvw.vdir[1] = 1.;
00410        setview(&cvw); beam_view(&cvw, 0, 0);
00411        cvw.vdir[0] = cvw.vdir[2] = 0.; cvw.vdir[1] = -1.;
00412        setview(&cvw); beam_view(&cvw, 0, 0);
00413        cvw.vdir[1] = cvw.vdir[2] = 0.; cvw.vdir[0] = 1.;
00414        setview(&cvw); beam_view(&cvw, 0, 0);
00415        cvw.vdir[1] = cvw.vdir[2] = 0.; cvw.vdir[0] = -1.;
00416        setview(&cvw); beam_view(&cvw, 0, 0);
00417                                    /* allocate new light set */
00418        dl = (DLIGHTS *)calloc(1, sizeof(DLIGHTS));
00419        if (dl == NULL)
00420               goto memerr;
00421        VCOPY(dl->lcent, ocent);
00422                                    /* push onto our light set list */
00423        dl->next = dlightsets;
00424        dlightsets = dl;
00425        dobj_lightsamp = ssph_sample;      /* get beams from server */
00426        imm_mode = beam_sync(-1) > 0;
00427        while (imm_mode)
00428               if (serv_result() == DS_SHUTDOWN)
00429                      quit(0);
00430        if (!ssph_compute()) {             /* compute light sources from sphere */
00431               dlightsets = dl->next;
00432               free((void *)dl);
00433               return(0);
00434        }
00435        op->ol = dl;
00436        return(1);
00437 memerr:
00438        error(SYSTEM, "out of memory in getdlights");
00439        return 0; /* pro forma return */
00440 }
00441 
00442 
00443 static void
00444 cmderror(            /* report command error */
00445        int    cn,
00446        char   *err
00447 )
00448 {
00449        sprintf(errmsg, "%s: %s", rhdcmd[cn], err);
00450        error(COMMAND, errmsg);
00451 }
00452 
00453 
00454 extern int
00455 dobj_command(        /* run object display command */
00456        char   *cmd,
00457        register char *args
00458 )
00459 {
00460        int    somechange = 0;
00461        int    cn, na;
00462        register int  nn;
00463        char   *alist[MAXAC+1], *nm;
00464                                    /* find command */
00465        for (cn = 0; cn < DO_NCMDS; cn++)
00466               if (!strcmp(cmd, rhdcmd[cn]))
00467                      break;
00468        if (cn >= DO_NCMDS)
00469               return(-1);          /* not in our list */
00470                                    /* make argument list */
00471        for (na = 0; *args; na++) {
00472               if (na > MAXAC)
00473                      goto toomany;
00474               alist[na] = args;
00475               while (*args && !isspace(*args))
00476                      args++;
00477               while (isspace(*args))
00478                      *args++ = '\0';
00479        }
00480        alist[na] = NULL;
00481                                    /* execute command */
00482        switch (cn) {
00483        case DO_LOAD:                      /* load an octree */
00484               if (na == 1)
00485                      dobj_load(alist[0], alist[0]);
00486               else if (na == 2)
00487                      dobj_load(alist[0], alist[1]);
00488               else {
00489                      cmderror(cn, "need octree [name]");
00490                      return(0);
00491               }
00492               break;
00493        case DO_UNLOAD:                           /* clear an object */
00494               if (na > 1) goto toomany;
00495               if (na && alist[0][0] == '*')
00496                      somechange += dobj_cleanup();
00497               else
00498                      somechange += dobj_unload(na ? alist[0] : curname);
00499               break;
00500        case DO_XFORM:                            /* transform object */
00501        case DO_MOVE:
00502               if (na && alist[0][0] != '-') {
00503                      nm = alist[0]; nn = 1;
00504               } else {
00505                      nm = curname; nn = 0;
00506               }
00507               if (cn == DO_MOVE && nn >= na) {
00508                      cmderror(cn, "missing transform");
00509                      return(0);
00510               }
00511               somechange += dobj_xform(nm, cn==DO_MOVE, na-nn, alist+nn);
00512               break;
00513        case DO_UNMOVE:                           /* undo last transform */
00514               somechange += dobj_unmove();
00515               break;
00516        case DO_OBJECT:                           /* print object statistics */
00517               if (dobj_putstats(na ? alist[0] : curname, sstdout))
00518                      if (na && alist[0][0] != '*' && (curobj == NULL ||
00519                                    strcmp(alist[0], curobj->name)))
00520                             savedxf(curobj = getdobj(alist[0]));
00521               break;
00522        case DO_DUP:                       /* duplicate object */
00523               for (nn = 0; nn < na; nn++)
00524                      if (alist[nn][0] == '-')
00525                             break;
00526               switch (nn) {
00527               case 0:
00528                      cmderror(cn, "need new object name");
00529                      return(0);
00530               case 1:
00531                      nm = curname;
00532                      break;
00533               case 2:
00534                      nm = alist[0];
00535                      break;
00536               default:
00537                      goto toomany;
00538               }
00539               if (!dobj_dup(nm, alist[nn-1]))
00540                      break;
00541               if (na > nn)
00542                      somechange += dobj_xform(curname, 1, na-nn, alist+nn);
00543               else
00544                      curobj->drawcode = DO_HIDE;
00545               savedxf(curobj);
00546               break;
00547        case DO_SHOW:                      /* change rendering option */
00548        case DO_LIGHT:
00549        case DO_HIDE:
00550               if (na > 1) goto toomany;
00551               dobj_lighting(na ? alist[0] : curname, cn);
00552               somechange++;
00553               break;
00554        default:
00555               error(CONSISTENCY, "bad command id in dobj_command");
00556        }
00557        return(somechange);
00558 toomany:
00559        cmderror(cn, "too many arguments");
00560        return(-1);
00561 }
00562 
00563 
00564 extern int
00565 dobj_load(           /* create/load an octree object */
00566        char   *oct,
00567        char   *nam
00568 )
00569 {
00570        char   *fpp, fpath[128];
00571        register DOBJECT     *op;
00572                                    /* check arguments */
00573        if (oct == NULL) {
00574               error(COMMAND, "missing octree");
00575               return(0);
00576        }
00577        if (nam == NULL) {
00578               error(COMMAND, "missing name");
00579               return(0);
00580        }
00581        if ((*nam == '*') | (*nam == '-')) {
00582               error(COMMAND, "illegal name");
00583               return(0);
00584        }
00585        if (getdobj(nam) != NULL) {
00586               error(COMMAND, "name already taken (clear first)");
00587               return(0);
00588        }
00589                                    /* get octree path */
00590        if ((fpp = getpath(oct, getrlibpath(), R_OK)) == NULL) {
00591               sprintf(errmsg, "cannot find octree \"%s\"", oct);
00592               error(COMMAND, errmsg);
00593               return(0);
00594        }
00595        strcpy(fpath, fpp);
00596        op = (DOBJECT *)malloc(sizeof(DOBJECT));
00597        if (op == NULL)
00598               error(SYSTEM, "out of memory in dobj_load");
00599                                    /* set struct fields */
00600        strcpy(op->name, nam);
00601        op->ol = NULL;
00602        op->drawcode = DO_HIDE;
00603        setident4(op->xfb.f.xfm); op->xfb.f.sca = 1.;
00604        setident4(op->xfb.b.xfm); op->xfb.b.sca = 1.;
00605        op->xfav[op->xfac=0] = NULL;
00606                                    /* load octree into display list */
00607        dolights = 0;
00608        domats = 1;
00609        op->listid = rgl_octlist(fpath, op->center, &op->radius, &op->nlists);
00610                                    /* start rtrace */
00611        rtargv[RTARGC-1] = fpath;
00612        rtargv[RTARGC] = NULL;
00613        open_process(&(op->rtp), rtargv);
00614                                    /* insert into main list */
00615        op->next = dobjects;
00616        curobj = dobjects = op;
00617        savedxf(NULL);
00618        return(1);
00619 }
00620 
00621 
00622 extern int
00623 dobj_unload(                /* free the named object */
00624        char   *nam
00625 )
00626 {
00627        register DOBJECT     *op;
00628 
00629        if ((op = getdobj(nam)) == NULL) {
00630               error(COMMAND, "no object");
00631               return(0);
00632        }
00633        freedobj(op);
00634        savedxf(curobj = NULL);
00635        return(1);
00636 }
00637 
00638 
00639 extern int
00640 dobj_cleanup(void)                        /* free all resources */
00641 {
00642        register DLIGHTS     *lp;
00643 
00644        while (dobjects != NULL)
00645               freedobj(dobjects);
00646        savedxf(curobj = NULL);
00647        while ((lp = dlightsets) != NULL) {
00648               dlightsets = lp->next;
00649               free((void *)lp);
00650        }
00651        return(1);
00652 }
00653 
00654 
00655 extern int
00656 dobj_xform(          /* set/add transform for nam */
00657        char   *nam,
00658        int    rel,
00659        int    ac,
00660        char   **av
00661 )
00662 {
00663        register DOBJECT     *op;
00664        FVECT  cent;
00665        double rad;
00666        char   scoord[16];
00667        int    i;
00668 
00669        if ((op = getdobj(nam)) == NULL) {
00670               error(COMMAND, "no object");
00671               return(0);
00672        }
00673        if (rel)
00674               rel = op->xfac + 8;
00675        if (ac + rel > MAXAC) {
00676               error(COMMAND, "too many transform arguments");
00677               return(0);
00678        }
00679        savedxf(curobj = op);              /* remember current transform */
00680        if (rel && ac == 4 && !strcmp(av[0], "-t"))
00681               rel = -1;                   /* don't move for translate */
00682        else {
00683               getdcent(cent, op);         /* don't move if near orig. */
00684               rad = getdrad(op);
00685               if (DOT(cent,cent) < rad*rad)
00686                      rel = -1;
00687        }
00688        if (!rel) {                        /* remove old transform */
00689               while (op->xfac)
00690                      freestr(op->xfav[--op->xfac]);
00691        } else if (rel > 0) {                     /* relative move */
00692               op->xfav[op->xfac++] = savestr("-t");
00693               for (i = 0; i < 3; i++) {
00694                      sprintf(scoord, "%.4e", -cent[i]);
00695                      op->xfav[op->xfac++] = savestr(scoord);
00696               }
00697        }
00698        while (ac--)
00699               op->xfav[op->xfac++] = savestr(*av++);
00700        if (rel > 0) {                            /* move back */
00701               op->xfav[op->xfac++] = savestr("-t");
00702               for (i = 0; i < 3; i++) {
00703                      sprintf(scoord, "%.4e", cent[i]);
00704                      op->xfav[op->xfac++] = savestr(scoord);
00705               }
00706        }
00707        op->xfav[op->xfac] = NULL;
00708        if (fullxf(&op->xfb, op->xfac, op->xfav) != op->xfac) {
00709               error(COMMAND, "bad transform arguments");
00710               dobj_unmove();
00711               savedxf(op);         /* save current transform instead */
00712               return(0);
00713        }
00714                                    /* don't know local lights anymore */
00715        getdlights(op, 0);
00716        return(1);
00717 }
00718 
00719 
00720 extern int
00721 dobj_putstats(                     /* put out statistics for nam */
00722        char   *nam,
00723        FILE   *fp
00724 )
00725 {
00726        FVECT  ocent;
00727        register DOBJECT     *op;
00728        register int  i;
00729 
00730        if (nam == NULL) {
00731               error(COMMAND, "no current object");
00732               return(0);
00733        }
00734        if (nam[0] == '*') {
00735               i = 0;
00736               for (op = dobjects; op != NULL; op = op->next)
00737                      i += dobj_putstats(op->name, fp);
00738               return(i);
00739        }
00740        if ((op = getdobj(nam)) == NULL) {
00741               error(COMMAND, "unknown object");
00742               return(0);
00743        }
00744        getdcent(ocent, op);
00745        fprintf(fp, "%s: %s, center [%g %g %g], radius %g", op->name,
00746                      op->drawcode==DO_HIDE ? "hidden" :
00747                      op->drawcode==DO_LIGHT && op->ol!=NULL ? "lighted" :
00748                      "shown",
00749                      ocent[0],ocent[1],ocent[2], getdrad(op));
00750        if (op->xfac)
00751               fputs(", (xform", fp);
00752        for (i = 0; i < op->xfac; i++) {
00753               putc(' ', fp);
00754               fputs(op->xfav[i], fp);
00755        }
00756        if (op->xfac)
00757               fputc(')', fp);
00758        fputc('\n', fp);
00759        return(1);
00760 }
00761 
00762 
00763 extern int
00764 dobj_unmove(void)                         /* undo last transform change */
00765 {
00766        int    txfac;
00767        char   *txfav[MAXAC+1];
00768 
00769        if (curobj == NULL) {
00770               error(COMMAND, "no current object");
00771               return(0);
00772        }
00773                                    /* hold last transform */
00774        memcpy((void *)txfav, (void *)lastxfav, 
00775                      (txfac=lastxfac)*sizeof(char *));
00776                                    /* save this transform */
00777        memcpy((void *)lastxfav, (void *)curobj->xfav, 
00778                      (lastxfac=curobj->xfac)*sizeof(char *));
00779                                    /* copy back last transform */
00780        memcpy((void *)curobj->xfav, (void *)txfav, 
00781                      (curobj->xfac=txfac)*sizeof(char *));
00782                                    /* set matrices */
00783        fullxf(&curobj->xfb, curobj->xfac, curobj->xfav);
00784                                    /* don't know local lights anymore */
00785        getdlights(curobj, 0);
00786        return(1);
00787 }
00788 
00789 
00790 extern int
00791 dobj_dup(                   /* duplicate object oldnm as nam */
00792        char   *oldnm,
00793        char   *nam
00794 )
00795 {
00796        register DOBJECT     *op, *opdup;
00797                                    /* check arguments */
00798        if ((op = getdobj(oldnm)) == NULL) {
00799               error(COMMAND, "no object");
00800               return(0);
00801        }
00802        if (nam == NULL) {
00803               error(COMMAND, "missing name");
00804               return(0);
00805        }
00806        if ((*nam == '*') | (*nam == '-')) {
00807               error(COMMAND, "illegal name");
00808               return(0);
00809        }
00810        if (getdobj(nam) != NULL) {
00811               error(COMMAND, "name already taken (clear first)");
00812               return(0);
00813        }
00814                                    /* allocate and copy struct */
00815        opdup = (DOBJECT *)malloc(sizeof(DOBJECT));
00816        if (opdup == NULL)
00817               error(SYSTEM, "out of memory in dobj_dup");
00818        *opdup = *op;
00819                                    /* rename */
00820        strcpy(opdup->name, nam);
00821                                    /* get our own copy of transform */
00822        for (opdup->xfac = 0; opdup->xfac < op->xfac; opdup->xfac++)
00823               opdup->xfav[opdup->xfac] = savestr(op->xfav[opdup->xfac]);
00824        opdup->xfav[opdup->xfac] = NULL;
00825                                    /* insert it into our list */
00826        opdup->next = dobjects;
00827        curobj = dobjects = opdup;
00828        return(1);
00829 }
00830 
00831 
00832 extern int
00833 dobj_lighting(              /* set up lighting for display object */
00834        char   *nam,
00835        int    cn
00836 )
00837 {
00838        int    i, res[2];
00839        VIEW   *dv;
00840        register DOBJECT     *op;
00841 
00842        if (nam == NULL) {
00843               error(COMMAND, "no current object");
00844               return(0);
00845        }
00846        if (nam[0] == '*') {
00847               for (op = dobjects; op != NULL; op = op->next)
00848                      if ((op->drawcode = cn) == DO_LIGHT)
00849                             getdlights(op, 1);
00850                      else
00851                             op->ol = NULL;
00852        } else if ((op = getdobj(nam)) == NULL) {
00853               error(COMMAND, "unknown object");
00854               return(0);
00855        } else if ((op->drawcode = cn) == DO_LIGHT) {
00856               if (!getdlights(op, 1))
00857                      error(COMMAND, "insufficient samples to light object");
00858        } else
00859               op->ol = NULL;
00860 
00861        if (dobj_lightsamp != NULL) {             /* restore beam set */
00862               dobj_lightsamp = NULL;
00863               beam_init(1);
00864               for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++)
00865                      beam_view(dv, res[0], res[1]);
00866               beam_sync(1);               /* update server */
00867        }
00868        return 0; /* XXX not sure if this is the right value */
00869 }
00870 
00871 
00872 extern double
00873 dobj_trace(   /* check for ray intersection with object(s) */
00874        char   nm[],
00875        FVECT  rorg,
00876        FVECT  rdir
00877 )
00878 {
00879        register DOBJECT     *op;
00880        FVECT  xorg, xdir;
00881        double darr[6];
00882                                    /* check each visible object? */
00883        if (nm == NULL || *nm == '*') {
00884               double dist, mindist = 1.01*FHUGE;
00885 
00886               if (nm != NULL) nm[0] = '\0';
00887               for (op = dobjects; op != NULL; op = op->next) {
00888                      if (op->drawcode == DO_HIDE)
00889                             continue;
00890                      dist = dobj_trace(op->name, rorg, rdir);
00891                      if (dist < mindist) {
00892                             if (nm != NULL) strcpy(nm, op->name);
00893                             mindist = dist;
00894                      }
00895               }
00896               return(mindist);
00897        }
00898                                    /* else check particular object */
00899        if ((op = getdobj(nm)) == NULL) {
00900               error(COMMAND, "unknown object");
00901               return(FHUGE);
00902        }
00903        if (op->xfac) {             /* put ray in local coordinates */
00904               multp3(xorg, rorg, op->xfb.b.xfm);
00905               multv3(xdir, rdir, op->xfb.b.xfm);
00906               VCOPY(darr, xorg); VCOPY(darr+3, xdir);
00907        } else {
00908               VCOPY(darr, rorg); VCOPY(darr+3, rdir);
00909        }
00910                             /* trace it */
00911        if (process(&(op->rtp), (char *)darr, (char *)darr, sizeof(double),
00912                      6*sizeof(double)) != sizeof(double))
00913               error(SYSTEM, "rtrace communication error");
00914                             /* return distance */
00915        if (darr[0] >= .99*FHUGE)
00916               return(FHUGE);
00917        return(darr[0]*op->xfb.f.sca);
00918 }
00919 
00920 
00921 extern int
00922 dobj_render(void)                  /* render our objects in OpenGL */
00923 {
00924        int    nrendered = 0;
00925        GLboolean     normalizing;
00926        GLfloat       vec[4];
00927        FVECT  v1;
00928        register DOBJECT     *op;
00929        register int  i;
00930                                    /* anything to render? */
00931        for (op = dobjects; op != NULL; op = op->next)
00932               if (op->drawcode != DO_HIDE)
00933                      break;
00934        if (op == NULL)
00935               return(0);
00936                                    /* set up general rendering params */
00937        glGetBooleanv(GL_NORMALIZE, &normalizing);
00938        glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT|GL_ENABLE_BIT|
00939               GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT);
00940        glDepthFunc(GL_LESS);
00941        glEnable(GL_DEPTH_TEST);
00942        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00943        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00944        glShadeModel(GL_SMOOTH);
00945        glFrontFace(GL_CCW);
00946        glDisable(GL_CULL_FACE);
00947        for (i = MAXLIGHTS; i--; )
00948               glDisable(glightid[i]);
00949        glEnable(GL_LIGHTING);
00950        rgl_checkerr("setting rendering modes in dobj_render");
00951                                    /* render each object */
00952        for (op = dobjects; op != NULL; op = op->next) {
00953               if (op->drawcode == DO_HIDE)
00954                      continue;
00955                                    /* set up lighting */
00956               if (op->drawcode == DO_LIGHT && op->ol != NULL) {
00957                      BYTE   pval;
00958                      double expval, d;
00959                                           /* use computed sources */
00960                      if (tmMapPixels(tmGlobal, &pval, &op->ol->larb,
00961                                    TM_NOCHROM, 1) != TM_E_OK)
00962                             error(CONSISTENCY, "dobj_render w/o tone map");
00963                      expval = pval * (WHTEFFICACY/256.) /
00964                                    tmLuminance(op->ol->larb);
00965                      vec[0] = expval * colval(op->ol->lamb,RED);
00966                      vec[1] = expval * colval(op->ol->lamb,GRN);
00967                      vec[2] = expval * colval(op->ol->lamb,BLU);
00968                      vec[3] = 1.;
00969                      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
00970                      for (i = op->ol->nl; i--; ) {
00971                             VCOPY(vec, op->ol->li[i].direc);
00972                             vec[3] = 0.;
00973                             glLightfv(glightid[i], GL_POSITION, vec);
00974                             d = expval * op->ol->li[i].omega;
00975                             vec[0] = d * colval(op->ol->li[i].val,RED);
00976                             vec[1] = d * colval(op->ol->li[i].val,GRN);
00977                             vec[2] = d * colval(op->ol->li[i].val,BLU);
00978                             vec[3] = 1.;
00979                             glLightfv(glightid[i], GL_SPECULAR, vec);
00980                             glLightfv(glightid[i], GL_DIFFUSE, vec);
00981                             vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
00982                             glLightfv(glightid[i], GL_AMBIENT, vec);
00983                             glEnable(glightid[i]);
00984                      }
00985               } else {                    /* fake lighting */
00986                      vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
00987                      glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
00988                      getdcent(v1, op);
00989                      VSUB(v1, odev.v.vp, v1);
00990                      if (normalize(v1) <= getdrad(op)) {
00991                             vec[0] = -odev.v.vdir[0];
00992                             vec[1] = -odev.v.vdir[1];
00993                             vec[2] = -odev.v.vdir[2];
00994                      } else
00995                             VCOPY(vec, v1);
00996                      vec[3] = 0.;
00997                      glLightfv(GL_LIGHT0, GL_POSITION, vec);
00998                      vec[0] = vec[1] = vec[2] = .7; vec[3] = 1.;
00999                      glLightfv(GL_LIGHT0, GL_SPECULAR, vec);
01000                      glLightfv(GL_LIGHT0, GL_DIFFUSE, vec);
01001                      vec[0] = vec[1] = vec[2] = .3; vec[3] = 1.;
01002                      glLightfv(GL_LIGHT0, GL_AMBIENT, vec);
01003                      glEnable(GL_LIGHT0);
01004               }
01005                                    /* set up object transform */
01006               if (op->xfac) {
01007                      if (!normalizing && (op->xfb.f.sca < 1.-FTINY) |
01008                                           (op->xfb.f.sca > 1.+FTINY))
01009                             glEnable(GL_NORMALIZE);
01010                      glMatrixMode(GL_MODELVIEW);
01011                      glPushMatrix();
01012                                    /* matrix order works out to same */
01013 #ifdef SMLFLT
01014                      glMultMatrixf((GLfloat *)op->xfb.f.xfm);
01015 #else
01016                      glMultMatrixd((GLdouble *)op->xfb.f.xfm);
01017 #endif
01018               }
01019                                    /* render the display list */
01020               glCallList(op->listid);
01021               nrendered++;
01022                                    /* restore matrix */
01023               if (op->xfac) {
01024                      glMatrixMode(GL_MODELVIEW);
01025                      glPopMatrix();
01026                      if (!normalizing)
01027                             glDisable(GL_NORMALIZE);
01028               }
01029                                    /* restore lighting */
01030               if (op->drawcode == DO_LIGHT && op->ol != NULL)
01031                      for (i = op->ol->nl; i--; )
01032                             glDisable(glightid[i]);
01033               else
01034                      glDisable(GL_LIGHT0);
01035                                    /* check errors */
01036        }
01037        glPopAttrib();                     /* restore rendering params */
01038        rgl_checkerr("rendering objects in dobj_render");
01039        return(nrendered);
01040 }