ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.1
Committed: Wed Aug 19 17:45:24 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

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