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