ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.2
Committed: Fri Aug 21 11:38:22 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.1: +75 -32 lines
Log Message:
changed dobj_trace() to return name of intersected object
improved "show" lighting with front-directed light source
changed MINTHRESH and cosmetic fixes

File Contents

# User Rev Content
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     dobj_putstats(na ? alist[0] : curname, sstdout);
486     break;
487     case DO_DUP: /* duplicate object */
488     for (nn = 0; nn < na; nn++)
489     if (alist[nn][0] == '-')
490     break;
491     switch (nn) {
492     case 0:
493     return(cmderror(cn, "need new object name"));
494     case 1:
495     nm = curname;
496     break;
497     case 2:
498     nm = alist[0];
499     break;
500     default:
501     goto toomany;
502     }
503     if (!dobj_dup(nm, alist[nn-1]))
504     break;
505     if (na > nn)
506     dobj_xform(curname, 1, na-nn, alist+nn);
507     else
508     curobj->drawcode = DO_HIDE;
509     break;
510     case DO_SHOW: /* change rendering option */
511     case DO_LIGHT:
512     case DO_HIDE:
513     if (na > 1) goto toomany;
514     dobj_lighting(na ? alist[0] : curname, cn);
515     break;
516     default:
517     error(CONSISTENCY, "bad command id in dobj_command");
518     }
519     dev_view(&odev.v); /* redraw */
520     return(cn);
521     toomany:
522     return(cmderror(cn, "too many arguments"));
523     }
524    
525    
526     dobj_load(oct, nam) /* create/load an octree object */
527     char *oct, *nam;
528     {
529     extern char *getlibpath(), *getpath();
530     char *fpp, fpath[128];
531     register DOBJECT *op;
532     /* check arguments */
533     if (oct == NULL) {
534     error(COMMAND, "missing octree");
535     return(0);
536     }
537     if (nam == NULL) {
538     error(COMMAND, "missing name");
539     return(0);
540     }
541     if (*nam == '*' | *nam == '-') {
542     error(COMMAND, "illegal name");
543     return(0);
544     }
545     /* get octree path */
546     if ((fpp = getpath(oct, getlibpath(), R_OK)) == NULL) {
547     sprintf(errmsg, "cannot find octree \"%s\"", oct);
548     error(COMMAND, errmsg);
549     return(0);
550     }
551     strcpy(fpath, fpp);
552     freedobj(getdobj(nam)); /* free previous use of nam */
553     op = (DOBJECT *)malloc(sizeof(DOBJECT));
554     if (op == NULL)
555     error(SYSTEM, "out of memory in dobj_load");
556     /* set struct fields */
557     strcpy(op->name, nam);
558     op->ol = NULL;
559     op->drawcode = DO_HIDE;
560     setident4(op->xfb.f.xfm); op->xfb.f.sca = 1.;
561     setident4(op->xfb.b.xfm); op->xfb.b.sca = 1.;
562     op->xfav[op->xfac=0] = NULL;
563     /* load octree into display list */
564     dolights = 0;
565     op->listid = rgl_octlist(fpath, op->center, &op->radius);
566     /* start rtrace */
567     rtargv[RTARGC-1] = fpath;
568     rtargv[RTARGC] = NULL;
569     open_process(op->rtp, rtargv);
570     /* insert into main list */
571     op->next = dobjects;
572     curobj = dobjects = op;
573     savedxf(NULL);
574     return(1);
575     }
576    
577    
578     dobj_unload(nam) /* free the named object */
579     char *nam;
580     {
581     register DOBJECT *op;
582    
583     if ((op = getdobj(nam)) == NULL) {
584     error(COMMAND, "no object");
585     return(0);
586     }
587     freedobj(op);
588     savedxf(curobj = NULL);
589     return(1);
590     }
591    
592    
593     dobj_cleanup() /* free all resources */
594     {
595     register DLIGHTS *lp;
596    
597     while (dobjects != NULL)
598     freedobj(dobjects);
599     savedxf(curobj = NULL);
600     while ((lp = dlightsets) != NULL) {
601     dlightsets = lp->next;
602     free((char *)lp);
603     }
604     return(1);
605     }
606    
607    
608     dobj_xform(nam, add, ac, av) /* set/add transform for nam */
609     char *nam;
610     int add, ac;
611     char **av;
612     {
613     register DOBJECT *op;
614    
615     if ((op = getdobj(nam)) == NULL) {
616     error(COMMAND, "no object");
617     return(0);
618     }
619     if (add) add = op->xfac;
620     if (ac + add > MAXAC) {
621     error(COMMAND, "too many transform arguments");
622     return(0);
623     }
624     savedxf(curobj = op);
625     if (!add)
626     while (op->xfac)
627     freestr(op->xfav[--op->xfac]);
628     while (ac--)
629     op->xfav[op->xfac++] = savestr(*av++);
630     op->xfav[op->xfac] = NULL;
631     if (fullxf(&op->xfb, op->xfac, op->xfav) != op->xfac) {
632     error(COMMAND, "bad transform arguments");
633     dobj_unmove();
634     savedxf(op); /* save current transform instead */
635     return(0);
636     }
637     /* don't know local lights anymore */
638     getdlights(op, 0);
639     return(1);
640     }
641    
642    
643     dobj_putstats(nam, fp) /* put out statistics for nam */
644     char *nam;
645     FILE *fp;
646     {
647     FVECT ocent;
648     register DOBJECT *op;
649     register int i;
650    
651     if (nam == NULL) {
652     error(COMMAND, "no current object");
653     return(0);
654     }
655     if (nam[0] == '*') {
656     i = 0;
657     for (op = dobjects; op != NULL; op = op->next)
658     i += dobj_putstats(op->name, fp);
659     return(i);
660     }
661     if ((op = getdobj(nam)) == NULL) {
662     error(COMMAND, "unknown object");
663     return(0);
664     }
665 gwlarson 3.2 getdcent(ocent, op);
666 gwlarson 3.1 fprintf(fp, "%s: %s, center [%f %f %f], radius %f", op->name,
667     op->drawcode==DO_HIDE ? "hid" :
668     op->drawcode==DO_LIGHT && op->ol!=NULL ? "lit" :
669     "shown",
670 gwlarson 3.2 ocent[0],ocent[1],ocent[2], getdrad(op));
671 gwlarson 3.1 if (op->xfac)
672     fputs(", (xform", fp);
673     for (i = 0; i < op->xfac; i++) {
674     putc(' ', fp);
675     fputs(op->xfav[i], fp);
676     }
677     if (op->xfac)
678     fputc(')', fp);
679     fputc('\n', fp);
680     return(1);
681     }
682    
683    
684     dobj_unmove() /* undo last transform change */
685     {
686     int txfac;
687     char *txfav[MAXAC+1];
688    
689     if (curobj == NULL) {
690     error(COMMAND, "no current object");
691     return(0);
692     }
693     /* hold last transform */
694     bcopy((char *)lastxfav, (char *)txfav,
695     (txfac=lastxfac)*sizeof(char *));
696     /* save this transform */
697     bcopy((char *)curobj->xfav, (char *)lastxfav,
698     (lastxfac=curobj->xfac)*sizeof(char *));
699     /* copy back last transform */
700     bcopy((char *)txfav, (char *)curobj->xfav,
701     (curobj->xfac=txfac)*sizeof(char *));
702     /* set matrices */
703     fullxf(&curobj->xfb, curobj->xfac, curobj->xfav);
704     /* don't know local lights anymore */
705     getdlights(curobj, 0);
706     return(1);
707     }
708    
709    
710     dobj_dup(oldnm, nam) /* duplicate object oldnm as nam */
711     char *oldnm, *nam;
712     {
713     register DOBJECT *op, *opdup;
714     /* check arguments */
715     if ((op = getdobj(oldnm)) == NULL) {
716     error(COMMAND, "no object");
717     return(0);
718     }
719     if (nam == NULL) {
720     error(COMMAND, "missing name");
721     return(0);
722     }
723     if (*nam == '*' | *nam == '-') {
724     error(COMMAND, "illegal name");
725     return(0);
726     }
727     /* allocate and copy struct */
728     opdup = (DOBJECT *)malloc(sizeof(DOBJECT));
729     if (opdup == NULL)
730     error(SYSTEM, "out of memory in dobj_dup");
731     copystruct(opdup, op);
732     /* rename */
733     strcpy(opdup->name, nam);
734     /* get our own copy of transform */
735     for (opdup->xfac = 0; opdup->xfac < op->xfac; opdup->xfac++)
736     opdup->xfav[opdup->xfac] = savestr(op->xfav[opdup->xfac]);
737     opdup->xfav[opdup->xfac] = NULL;
738     /* insert it into our list */
739     opdup->next = dobjects;
740     curobj = dobjects = opdup;
741     return(1);
742     }
743    
744    
745     dobj_lighting(nam, cn) /* set up lighting for display object */
746     char *nam;
747     int cn;
748     {
749     int i, res[2];
750     VIEW *dv;
751     register DOBJECT *op;
752    
753     if (nam == NULL) {
754     error(COMMAND, "no current object");
755     return(0);
756     }
757     if (nam[0] == '*') {
758     for (op = dobjects; op != NULL; op = op->next)
759     if ((op->drawcode = cn) == DO_LIGHT)
760     getdlights(op, 1);
761     else
762     op->ol = NULL;
763     } else if ((op = getdobj(nam)) == NULL) {
764     error(COMMAND, "unknown object");
765     return(0);
766     } else if ((op->drawcode = cn) == DO_LIGHT)
767     getdlights(op, 1);
768     else
769     op->ol = NULL;
770    
771     if (dobj_lightsamp != NULL) { /* restore beam set */
772     dobj_lightsamp = NULL;
773     beam_init(1);
774     for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++)
775     beam_view(dv, res[0], res[1]);
776     beam_sync(1); /* update server */
777     }
778     }
779    
780    
781     double
782 gwlarson 3.2 dobj_trace(nm, rorg, rdir) /* check for ray intersection with object(s) */
783     char nm[];
784 gwlarson 3.1 FVECT rorg, rdir;
785     {
786     register DOBJECT *op;
787     FVECT xorg, xdir;
788 gwlarson 3.2 double darr[6];
789    
790     if (nm == NULL || *nm == '*') {
791     double dist, mindist = 1.01*FHUGE;
792 gwlarson 3.1 /* check each visible object */
793 gwlarson 3.2 for (op = dobjects; op != NULL; op = op->next) {
794     if (op->drawcode == DO_HIDE)
795     continue;
796     dist = dobj_trace(op->name, rorg, rdir);
797     if (dist < mindist) {
798     dist = mindist;
799     if (nm != NULL)
800     strcpy(nm, op->name);
801     }
802 gwlarson 3.1 }
803 gwlarson 3.2 return(mindist);
804 gwlarson 3.1 }
805 gwlarson 3.2 /* else check particular object */
806     if ((op = getdobj(nm)) == NULL) {
807     error(COMMAND, "unknown object");
808     return(FHUGE);
809     }
810     if (op->xfac) { /* transform ray */
811     multp3(xorg, rorg, op->xfb.b.xfm);
812     multv3(xdir, rdir, op->xfb.b.xfm);
813     VCOPY(darr, xorg); VCOPY(darr+3, xdir);
814     } else {
815     VCOPY(darr, rorg); VCOPY(darr+3, rdir);
816     }
817     /* trace it */
818     if (process(op->rtp, darr, darr, sizeof(double),
819     6*sizeof(double)) != sizeof(double))
820     error(SYSTEM, "rtrace communication error");
821     /* return distance */
822     if (darr[0] >= .99*FHUGE)
823     return(FHUGE);
824     return(darr[0] * op->xfb.f.sca);
825 gwlarson 3.1 }
826    
827    
828     dobj_render() /* render our objects in OpenGL */
829     {
830     GLboolean normalizing;
831     GLfloat vec[4];
832 gwlarson 3.2 FVECT v1;
833 gwlarson 3.1 register DOBJECT *op;
834     register int i;
835     /* anything to render? */
836     for (op = dobjects; op != NULL; op = op->next)
837     if (op->drawcode != DO_HIDE)
838     break;
839     if (op == NULL)
840     return(1);
841     /* set up general rendering params */
842     glGetBooleanv(GL_NORMALIZE, &normalizing);
843     glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT|
844     GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT);
845     glDepthFunc(GL_LESS);
846     glEnable(GL_DEPTH_TEST);
847     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
848     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
849     glShadeModel(GL_SMOOTH);
850     glFrontFace(GL_CCW);
851     glDisable(GL_CULL_FACE);
852     for (i = MAXLIGHTS; i--; )
853     glDisable(glightid[i]);
854     glEnable(GL_LIGHTING);
855     rgl_checkerr("setting rendering modes in dobj_render");
856     /* render each object */
857     for (op = dobjects; op != NULL; op = op->next) {
858     if (op->drawcode == DO_HIDE)
859     continue;
860     /* set up lighting */
861     if (op->drawcode == DO_LIGHT && op->ol != NULL) {
862     BYTE pval;
863     double expval, d;
864 gwlarson 3.2 /* use computed sources */
865 gwlarson 3.1 if (tmMapPixels(&pval, &op->ol->larb, TM_NOCHROM, 1)
866     != TM_E_OK)
867     error(CONSISTENCY, "dobj_render w/o tone map");
868     expval = pval * (WHTEFFICACY/256.) /
869     tmLuminance(op->ol->larb);
870     vec[0] = expval * colval(op->ol->lamb,RED);
871     vec[1] = expval * colval(op->ol->lamb,GRN);
872     vec[2] = expval * colval(op->ol->lamb,BLU);
873     vec[3] = 1.;
874     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
875     for (i = op->ol->nl; i--; ) {
876     VCOPY(vec, op->ol->li[i].direc);
877     vec[3] = 0.;
878     glLightfv(glightid[i], GL_POSITION, vec);
879     d = expval * op->ol->li[i].omega;
880     vec[0] = d * colval(op->ol->li[i].val,RED);
881     vec[1] = d * colval(op->ol->li[i].val,GRN);
882     vec[2] = d * colval(op->ol->li[i].val,BLU);
883     vec[3] = 1.;
884     glLightfv(glightid[i], GL_SPECULAR, vec);
885     glLightfv(glightid[i], GL_DIFFUSE, vec);
886     vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
887     glLightfv(glightid[i], GL_AMBIENT, vec);
888     glEnable(glightid[i]);
889     }
890 gwlarson 3.2 } else { /* no sources to draw on */
891     vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
892 gwlarson 3.1 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
893 gwlarson 3.2 getdcent(v1, op);
894     VSUB(v1, odev.v.vp, v1);
895     if (normalize(v1) <= getdrad(op)) {
896     vec[0] = -odev.v.vdir[0];
897     vec[1] = -odev.v.vdir[1];
898     vec[2] = -odev.v.vdir[2];
899     } else
900     VCOPY(vec, v1);
901     vec[3] = 0.;
902     glLightfv(GL_LIGHT0, GL_POSITION, vec);
903     vec[0] = vec[1] = vec[2] = .7; vec[3] = 1.;
904     glLightfv(GL_LIGHT0, GL_SPECULAR, vec);
905     glLightfv(GL_LIGHT0, GL_DIFFUSE, vec);
906     vec[0] = vec[1] = vec[2] = .3; vec[3] = 1.;
907     glLightfv(GL_LIGHT0, GL_AMBIENT, vec);
908     glEnable(GL_LIGHT0);
909 gwlarson 3.1 }
910     /* set up object transform */
911     if (op->xfac) {
912     if (!normalizing && op->xfb.f.sca < 1.-FTINY |
913     op->xfb.f.sca > 1.+FTINY)
914     glEnable(GL_NORMALIZE);
915     glMatrixMode(GL_MODELVIEW);
916     glPushMatrix();
917     /* matrix order works out to same */
918     #ifdef SMLFLT
919     glMultMatrixf((GLfloat *)op->xfb.f.xfm);
920     #else
921     glMultMatrixd((GLdouble *)op->xfb.f.xfm);
922     #endif
923     }
924     /* render the display list */
925     glCallList(op->listid);
926     /* restore matrix */
927     if (op->xfac) {
928     glMatrixMode(GL_MODELVIEW);
929     glPopMatrix();
930     if (!normalizing)
931     glDisable(GL_NORMALIZE);
932     }
933     /* restore lighting */
934     if (op->drawcode == DO_LIGHT && op->ol != NULL)
935     for (i = op->ol->nl; i--; )
936     glDisable(glightid[i]);
937 gwlarson 3.2 else
938     glDisable(GL_LIGHT0);
939 gwlarson 3.1 /* check errors */
940     rgl_checkerr("rendering object in dobj_render");
941     }
942     glPopAttrib(); /* restore rendering params */
943     return(1);
944     }