ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.3
Committed: Tue Aug 25 18:10:12 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.2: +24 -13 lines
Log Message:
minor improvements

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 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     } else if ((op->drawcode = cn) == DO_LIGHT)
778     getdlights(op, 1);
779     else
780     op->ol = NULL;
781    
782     if (dobj_lightsamp != NULL) { /* restore beam set */
783     dobj_lightsamp = NULL;
784     beam_init(1);
785     for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++)
786     beam_view(dv, res[0], res[1]);
787     beam_sync(1); /* update server */
788     }
789     }
790    
791    
792     double
793 gwlarson 3.2 dobj_trace(nm, rorg, rdir) /* check for ray intersection with object(s) */
794     char nm[];
795 gwlarson 3.1 FVECT rorg, rdir;
796     {
797     register DOBJECT *op;
798     FVECT xorg, xdir;
799 gwlarson 3.2 double darr[6];
800 gwlarson 3.3 /* check each visible object? */
801 gwlarson 3.2 if (nm == NULL || *nm == '*') {
802     double dist, mindist = 1.01*FHUGE;
803 gwlarson 3.3
804     if (nm != NULL) nm[0] = '\0';
805 gwlarson 3.2 for (op = dobjects; op != NULL; op = op->next) {
806     if (op->drawcode == DO_HIDE)
807     continue;
808     dist = dobj_trace(op->name, rorg, rdir);
809     if (dist < mindist) {
810 gwlarson 3.3 if (nm != NULL) strcpy(nm, op->name);
811     mindist = dist;
812 gwlarson 3.2 }
813 gwlarson 3.1 }
814 gwlarson 3.2 return(mindist);
815 gwlarson 3.1 }
816 gwlarson 3.2 /* else check particular object */
817     if ((op = getdobj(nm)) == NULL) {
818     error(COMMAND, "unknown object");
819     return(FHUGE);
820     }
821 gwlarson 3.3 if (op->xfac) { /* put ray in local coordinates */
822 gwlarson 3.2 multp3(xorg, rorg, op->xfb.b.xfm);
823     multv3(xdir, rdir, op->xfb.b.xfm);
824     VCOPY(darr, xorg); VCOPY(darr+3, xdir);
825     } else {
826     VCOPY(darr, rorg); VCOPY(darr+3, rdir);
827     }
828     /* trace it */
829     if (process(op->rtp, darr, darr, sizeof(double),
830     6*sizeof(double)) != sizeof(double))
831     error(SYSTEM, "rtrace communication error");
832     /* return distance */
833     if (darr[0] >= .99*FHUGE)
834     return(FHUGE);
835 gwlarson 3.3 return(darr[0]*op->xfb.f.sca);
836 gwlarson 3.1 }
837    
838    
839     dobj_render() /* render our objects in OpenGL */
840     {
841     GLboolean normalizing;
842     GLfloat vec[4];
843 gwlarson 3.2 FVECT v1;
844 gwlarson 3.1 register DOBJECT *op;
845     register int i;
846     /* anything to render? */
847     for (op = dobjects; op != NULL; op = op->next)
848     if (op->drawcode != DO_HIDE)
849     break;
850     if (op == NULL)
851     return(1);
852     /* set up general rendering params */
853     glGetBooleanv(GL_NORMALIZE, &normalizing);
854     glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT|
855     GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT);
856     glDepthFunc(GL_LESS);
857     glEnable(GL_DEPTH_TEST);
858     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
859     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
860     glShadeModel(GL_SMOOTH);
861     glFrontFace(GL_CCW);
862     glDisable(GL_CULL_FACE);
863     for (i = MAXLIGHTS; i--; )
864     glDisable(glightid[i]);
865     glEnable(GL_LIGHTING);
866     rgl_checkerr("setting rendering modes in dobj_render");
867     /* render each object */
868     for (op = dobjects; op != NULL; op = op->next) {
869     if (op->drawcode == DO_HIDE)
870     continue;
871     /* set up lighting */
872     if (op->drawcode == DO_LIGHT && op->ol != NULL) {
873     BYTE pval;
874     double expval, d;
875 gwlarson 3.2 /* use computed sources */
876 gwlarson 3.1 if (tmMapPixels(&pval, &op->ol->larb, TM_NOCHROM, 1)
877     != TM_E_OK)
878     error(CONSISTENCY, "dobj_render w/o tone map");
879     expval = pval * (WHTEFFICACY/256.) /
880     tmLuminance(op->ol->larb);
881     vec[0] = expval * colval(op->ol->lamb,RED);
882     vec[1] = expval * colval(op->ol->lamb,GRN);
883     vec[2] = expval * colval(op->ol->lamb,BLU);
884     vec[3] = 1.;
885     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
886     for (i = op->ol->nl; i--; ) {
887     VCOPY(vec, op->ol->li[i].direc);
888     vec[3] = 0.;
889     glLightfv(glightid[i], GL_POSITION, vec);
890     d = expval * op->ol->li[i].omega;
891     vec[0] = d * colval(op->ol->li[i].val,RED);
892     vec[1] = d * colval(op->ol->li[i].val,GRN);
893     vec[2] = d * colval(op->ol->li[i].val,BLU);
894     vec[3] = 1.;
895     glLightfv(glightid[i], GL_SPECULAR, vec);
896     glLightfv(glightid[i], GL_DIFFUSE, vec);
897     vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
898     glLightfv(glightid[i], GL_AMBIENT, vec);
899     glEnable(glightid[i]);
900     }
901 gwlarson 3.3 } else { /* fake lighting */
902 gwlarson 3.2 vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
903 gwlarson 3.1 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
904 gwlarson 3.2 getdcent(v1, op);
905     VSUB(v1, odev.v.vp, v1);
906     if (normalize(v1) <= getdrad(op)) {
907     vec[0] = -odev.v.vdir[0];
908     vec[1] = -odev.v.vdir[1];
909     vec[2] = -odev.v.vdir[2];
910     } else
911     VCOPY(vec, v1);
912     vec[3] = 0.;
913     glLightfv(GL_LIGHT0, GL_POSITION, vec);
914     vec[0] = vec[1] = vec[2] = .7; vec[3] = 1.;
915     glLightfv(GL_LIGHT0, GL_SPECULAR, vec);
916     glLightfv(GL_LIGHT0, GL_DIFFUSE, vec);
917     vec[0] = vec[1] = vec[2] = .3; vec[3] = 1.;
918     glLightfv(GL_LIGHT0, GL_AMBIENT, vec);
919     glEnable(GL_LIGHT0);
920 gwlarson 3.1 }
921     /* set up object transform */
922     if (op->xfac) {
923     if (!normalizing && op->xfb.f.sca < 1.-FTINY |
924     op->xfb.f.sca > 1.+FTINY)
925     glEnable(GL_NORMALIZE);
926     glMatrixMode(GL_MODELVIEW);
927     glPushMatrix();
928     /* matrix order works out to same */
929     #ifdef SMLFLT
930     glMultMatrixf((GLfloat *)op->xfb.f.xfm);
931     #else
932     glMultMatrixd((GLdouble *)op->xfb.f.xfm);
933     #endif
934     }
935     /* render the display list */
936     glCallList(op->listid);
937     /* restore matrix */
938     if (op->xfac) {
939     glMatrixMode(GL_MODELVIEW);
940     glPopMatrix();
941     if (!normalizing)
942     glDisable(GL_NORMALIZE);
943     }
944     /* restore lighting */
945     if (op->drawcode == DO_LIGHT && op->ol != NULL)
946     for (i = op->ol->nl; i--; )
947     glDisable(glightid[i]);
948 gwlarson 3.2 else
949     glDisable(GL_LIGHT0);
950 gwlarson 3.1 /* check errors */
951     }
952     glPopAttrib(); /* restore rendering params */
953 gwlarson 3.3 rgl_checkerr("rendering objects in dobj_render");
954 gwlarson 3.1 return(1);
955     }