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