Back to index

radiance  4R0+20100331
rglinst.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: rglinst.c,v 3.15 2004/05/25 22:04:13 greg Exp $";
00003 #endif
00004 /*
00005  * Routines for reading instances and converting to OpenGL.
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include <stdio.h>
00011 #include <string.h>
00012 #include <time.h>
00013 
00014 #include "platform.h"
00015 #include "paths.h"
00016 #include "resolu.h"
00017 #include "radogl.h"
00018 #include "octree.h"
00019 
00020 #define MAXLEVEL     16            /* maximum instance hierarchy level */
00021 
00022 typedef struct {
00023        int    listid;                            /* our list id */
00024        short  localmatl;                  /* uses local material only */
00025        FVECT  cent;                       /* center of octree cube */
00026        char   octfile[256];               /* octree file path */
00027 } OCTINST;                         /* octree to instantiate */
00028 
00029 static double  ogetflt(void);
00030 static long  ogetint(int);
00031 static char  *ogetstr(char *);
00032 static int  loadobj(void);
00033 static void  skiptree(void);
00034 static void  octerror(int etyp, char *msg);
00035 static OCTINST       *getoct(char *);
00036 
00037 static char  *infn;                /* input file name */
00038 static FILE  *infp;                /* input file stream */
00039 static int  objsize;               /* size of stored OBJECT's */
00040 static short  otypmap[NUMOTYPE+8]; /* object type map */
00041 
00042 static unsigned long imhash(mod) char *mod; {return((unsigned long)mod);}
00043 static LUTAB  imtab = {imhash,NULL,NULL,NULL,0,NULL,0};
00044 
00045 static LUTAB  ottab = LU_SINIT(free,free);
00046 
00047 
00048 int
00049 o_instance(o)                      /* convert instance to list call */
00050 register OBJREC      *o;
00051 {
00052        XF     xfs;
00053        register OCTINST     *ot;
00054                                    /* set up */
00055        if (o->oargs.nsargs < 1)
00056               objerror(o, USER, "missing octree");
00057        setmaterial(NULL, NULL, 0);
00058                                    /* put out transform (if any) */
00059        if (o->oargs.nsargs > 1) {
00060               if (xf(&xfs, o->oargs.nsargs-1, o->oargs.sarg+1) !=
00061                             o->oargs.nsargs-1)
00062                      objerror(o, USER, "bad transform");
00063               glPushAttrib(GL_TRANSFORM_BIT);
00064               if ((xfs.sca < 1.-FTINY) | (xfs.sca > 1.+FTINY))
00065                      glEnable(GL_NORMALIZE);
00066               glMatrixMode(GL_MODELVIEW);
00067               glPushMatrix();
00068                                    /* matrix order works out to same */
00069 #ifdef SMLFLT
00070               glMultMatrixf((GLfloat *)xfs.xfm);
00071 #else
00072               glMultMatrixd((GLdouble *)xfs.xfm);
00073 #endif
00074        }
00075        ot = getoct(o->oargs.sarg[0]);     /* get octree reference */
00076        if (ot->localmatl &= o->os != NULL)       /* set material */
00077               setmaterial((MATREC *)o->os, ot->cent, 0);
00078                                    /* call the assigned list */
00079        glCallList(ot->listid);
00080 
00081        if (o->oargs.nsargs > 1) {  /* end transform */
00082               glMatrixMode(GL_MODELVIEW);
00083               glPopMatrix();
00084               glPopAttrib();
00085        }
00086        rgl_checkerr("creating instance");
00087        return(0);
00088 }
00089 
00090 
00091 static int
00092 buildoctlist(lp, p)                /* build octree list */
00093 const LUENT   *lp;
00094 void   *p;
00095 {
00096        int    old_dolights = dolights, old_domats = domats;
00097        register OCTINST     *op = (OCTINST *)lp->data;
00098 
00099        domats = !op->localmatl;    /* do materials only if needed */
00100        dolights = 0;               /* never do light sources */
00101        glNewList(op->listid, GL_COMPILE);
00102        loadoct(op->octfile);              /* load objects into display list */
00103        surfclean();                /* clean up */
00104        glEndList();
00105        dolights = old_dolights;    /* restore */
00106        domats = old_domats;
00107        return(1);                  /* return success */
00108 }
00109 
00110 
00111 int
00112 loadoctrees()                      /* load octrees we've saved up */
00113 {
00114        int    levelsleft = MAXLEVEL;
00115        int    nocts = 0;
00116        LUTAB  looptab;
00117                             /* loop through new octree references */
00118        while (ottab.tsiz) {
00119               if (!levelsleft--)
00120                      error(USER, "too many octree levels -- instance loop?");
00121               looptab = ottab;
00122               ottab.tsiz = 0;
00123               nocts += lu_doall(&looptab, buildoctlist, NULL);
00124               lu_done(&looptab);
00125        }
00126        return(nocts);
00127 }
00128 
00129 
00130 static OCTINST *
00131 getoct(name)                       /* get/assign octree list id */
00132 char   *name;
00133 {
00134        char   *path;
00135        register LUENT       *lp;
00136        register OCTINST     *op;
00137 
00138        if ((lp = lu_find(&ottab, name)) == NULL)
00139               goto memerr;
00140        if (lp->key == NULL) {
00141               lp->key = (char *)malloc(strlen(name)+1);
00142               if (lp->key == NULL)
00143                      goto memerr;
00144               strcpy(lp->key, name);
00145        }
00146        if ((op = (OCTINST *)lp->data) == NULL) {
00147               path = getpath(name, getrlibpath(), R_OK);
00148               if (path == NULL) {
00149                      sprintf(errmsg, "cannot find octree \"%s\"", name);
00150                      error(USER, errmsg);
00151               }
00152               op = (OCTINST *)(lp->data = (char *)malloc(sizeof(OCTINST)));
00153               strcpy(op->octfile, path);
00154               checkoct(op->octfile, op->cent);
00155               op->listid = newglist();
00156               op->localmatl = ~0;
00157        }
00158        return(op);
00159 memerr:
00160        error(SYSTEM, "out of memory in getoct");
00161        return NULL; /* pro forma return */
00162 }
00163 
00164 
00165 double
00166 checkoct(fname, cent)                     /* check octree file for validity */
00167 char   *fname;
00168 FVECT  cent;
00169 {
00170        char  sbuf[64];
00171        FILE   *fp = infp;
00172        char   *fn = infn;
00173        double siz = 0.;
00174        register int  i;
00175        
00176        if ((infp = fopen(infn=fname, "r")) == NULL) {
00177               sprintf(errmsg, "cannot open octree file \"%s\"", fname);
00178               error(SYSTEM, errmsg);
00179        }
00180        SET_FILE_BINARY(infp);
00181                                    /* get header */
00182        if (checkheader(infp, OCTFMT, NULL) < 0)
00183               octerror(USER, "not an octree");
00184                                    /* check format */
00185        if ((objsize = ogetint(2)-OCTMAGIC) <= 0 ||
00186                      objsize > MAXOBJSIZ || objsize > sizeof(long))
00187               octerror(USER, "incompatible octree format");
00188        if (cent != NULL) {         /* get boundaries (compute center) */
00189               for (i = 0; i < 3; i++)
00190                      cent[i] = atof(ogetstr(sbuf));
00191               siz = atof(ogetstr(sbuf))*.5;
00192               cent[0] += siz; cent[1] += siz; cent[2] += siz;
00193        } else {                    /* get size (radius) only */
00194               for (i = 0; i < 3; i++)
00195                      ogetstr(sbuf);
00196               siz = atof(ogetstr(sbuf))*.5;
00197        }
00198        fclose(infp);
00199        infp = fp;
00200        infn = fn;
00201        return(siz);
00202 }
00203 
00204 
00205 int
00206 loadoct(fname)                            /* read in objects from octree */
00207 char  *fname;
00208 {
00209        OBJECT  fnobjects;
00210        char  sbuf[256];
00211        int  nf;
00212        register int  i;
00213        long  m;
00214        
00215        infn = fname;
00216        infp = fopen(fname, "r");   /* assume already checked */
00217        SET_FILE_BINARY(infp);
00218                                    /* skip header */
00219        getheader(infp, NULL, NULL);
00220                                    /* get format */
00221        objsize = ogetint(2)-OCTMAGIC;
00222                                    /* skip boundaries */
00223        for (i = 0; i < 4; i++)
00224               ogetstr(sbuf);
00225        nf = 0;                            /* load object files */
00226        while (*ogetstr(sbuf)) {
00227               rgl_load(sbuf);
00228               nf++;
00229        }
00230                                    /* get number of objects */
00231        fnobjects = m = ogetint(objsize);
00232        if (fnobjects != m)
00233               octerror(USER, "too many objects");
00234 
00235        if (nf == 0) {
00236               skiptree();
00237               for (i = 0; *ogetstr(sbuf); i++)
00238                      if ((otypmap[i] = otype(sbuf)) < 0) {
00239                             sprintf(errmsg, "unknown type \"%s\"", sbuf);
00240                             octerror(WARNING, errmsg);
00241                      }
00242               lu_init(&imtab, 1000); nobjects = 0;
00243               while (loadobj() != OVOID)
00244                      ;
00245               lu_done(&imtab);
00246               if (nobjects != fnobjects)
00247                      octerror(USER, "inconsistent object count");
00248        }
00249        fclose(infp);
00250        return(nf);
00251 }
00252 
00253 
00254 static char *
00255 ogetstr(s)                  /* get null-terminated string */
00256 char  *s;
00257 {
00258        extern char  *getstr();
00259 
00260        if (getstr(s, infp) == NULL)
00261               octerror(USER, "truncated octree");
00262        return(s);
00263 }
00264 
00265 
00266 static long
00267 ogetint(siz)                /* get a siz-byte integer */
00268 int  siz;
00269 {
00270        extern long  getint();
00271        register long  r;
00272 
00273        r = getint(siz, infp);
00274        if (feof(infp))
00275               octerror(USER, "truncated octree");
00276        return(r);
00277 }
00278 
00279 
00280 static double
00281 ogetflt()                   /* get a floating point number */
00282 {
00283        extern double  getflt();
00284        double r;
00285 
00286        r = getflt(infp);
00287        if (feof(infp))
00288               octerror(USER, "truncated octree");
00289        return(r);
00290 }
00291        
00292 
00293 static void
00294 skiptree()                         /* skip octree on input */
00295 {
00296        register int  i;
00297        
00298        switch (getc(infp)) {
00299        case OT_EMPTY:
00300               return;
00301        case OT_FULL:
00302               for (i = ogetint(objsize)*objsize; i-- > 0; )
00303                      if (getc(infp) == EOF)
00304                             octerror(USER, "truncated octree");
00305               return;
00306        case OT_TREE:
00307               for (i = 0; i < 8; i++)
00308                      skiptree();
00309               return;
00310        case EOF:
00311               octerror(USER, "truncated octree");
00312        default:
00313               octerror(USER, "damaged octree");
00314        }
00315 }
00316 
00317 
00318 static int
00319 loadobj()                          /* get next object */
00320 {
00321        static OBJREC  ob;
00322        char  idbuf[MAXSTR], sbuf[MAXSTR];
00323        register LUENT       *lep;
00324        register int  i;
00325        register long  m;
00326                                    /* get type */
00327        i = ogetint(1);
00328        if (i == -1)
00329               return(OVOID);              /* terminator */
00330        if ((ob.otype = otypmap[i]) < 0)
00331               octerror(USER, "reference to unknown type");
00332                                    /* get modifier */
00333        if ((m = ogetint(objsize)) != OVOID && (OBJECT)m != m)
00334               octerror(USER, "too many objects");
00335        if ((ob.omod = m) != OVOID && domats) {
00336               if ((lep = lu_find(&imtab, (char *)m)) == NULL)
00337                      goto memerr;
00338               ob.os = lep->data;
00339        } else
00340               ob.os = NULL;
00341                                    /* get name id */
00342        ob.oname = ogetstr(idbuf);
00343                                    /* get string arguments */
00344        if ((ob.oargs.nsargs = ogetint(2))) {
00345               ob.oargs.sarg = (char **)malloc
00346                             (ob.oargs.nsargs*sizeof(char *));
00347               if (ob.oargs.sarg == NULL)
00348                      goto memerr;
00349               for (i = 0; i < ob.oargs.nsargs; i++)
00350                      ob.oargs.sarg[i] = savestr(ogetstr(sbuf));
00351        } else
00352               ob.oargs.sarg = NULL;
00353                                    /* get integer arguments */
00354 #ifdef IARGS
00355        if (ob.oargs.niargs = ogetint(2)) {
00356               ob.oargs.iarg = (long *)malloc
00357                             (ob.oargs.niargs*sizeof(long));
00358               if (ob.oargs.iarg == NULL)
00359                      goto memerr;
00360               for (i = 0; i < ob.oargs.niargs; i++)
00361                      ob.oargs.iarg[i] = ogetint(4);
00362        } else
00363               ob.oargs.iarg = NULL;
00364 #endif
00365                                    /* get real arguments */
00366        if ((ob.oargs.nfargs = ogetint(2))) {
00367               ob.oargs.farg = (RREAL *)malloc
00368                             (ob.oargs.nfargs*sizeof(RREAL));
00369               if (ob.oargs.farg == NULL)
00370                      goto memerr;
00371               for (i = 0; i < ob.oargs.nfargs; i++)
00372                      ob.oargs.farg[i] = ogetflt();
00373        } else
00374               ob.oargs.farg = NULL;
00375                                    /* process object */
00376        (*ofun[ob.otype].funp)(&ob);
00377                                    /* record material if modifier */
00378        if (ismodifier(ob.otype)) {
00379               if ((lep = lu_find(&imtab, (char *)nobjects)) == NULL)
00380                      goto memerr;
00381               lep->key = (char *)nobjects;
00382               lep->data = (char *)getmatp(ob.oname);
00383        }
00384        freefargs(&ob.oargs);              /* free arguments */
00385        return(nobjects++);         /* return object id */
00386 memerr:
00387        error(SYSTEM, "out of memory in loadobj");
00388        return OVOID; /* pro forma return */
00389 }
00390 
00391 
00392 static void
00393 octerror(etyp, msg)                /* octree error */
00394 int  etyp;
00395 char  *msg;
00396 {
00397        char  msgbuf[128];
00398 
00399        sprintf(msgbuf, "(%s): %s", infn, msg);
00400        error(etyp, msgbuf);
00401 }