ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.6
Committed: Fri Oct 9 17:34:00 1998 UTC (25 years, 6 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.5: +38 -9 lines
Log Message:
changed moved command to do rotations and scaling relative to object center

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 gwlarson 3.5 * Routines for loading and displaying Radiance objects in rholo with GLX.
9 gwlarson 3.1 */
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 gwlarson 3.6 #define MAXAC 512 /* maximum number of args */
26 gwlarson 3.1
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 gwlarson 3.6 ls->omega += 1.;
324 gwlarson 3.1 addcolor(ls->val, ssamp[alt][azi].val);
325 gwlarson 3.6 /* remove from list */
326 gwlarson 3.1 setcolor(ssamp[alt][azi].val, 0., 0., 0.);
327 gwlarson 3.6 ssamp[alt][azi].nsamp = 0;
328 gwlarson 3.1 }
329     d = 1./ls->omega; /* avg. brightness */
330     scalecolor(ls->val, d);
331     ls->omega *= 4.*PI/(NALT*NAZI); /* solid angle */
332     normalize(ls->direc); /* direction */
333     }
334     /* compute ambient remainder */
335     for (alt = 0; alt < NALT; alt++)
336     for (azi = 0; azi < NAZI; azi++)
337     if (ssamp[alt][azi].nsamp)
338     addcolor(dlightsets->lamb, ssamp[alt][azi].val);
339     d = 1.0/ncells;
340     scalecolor(dlightsets->lamb, d);
341 gwlarson 3.2 done: /* clear sphere sample array */
342 gwlarson 3.1 bzero((char *)ssamp, sizeof(ssamp));
343     return(ncells);
344     }
345    
346    
347     static
348     getdlights(op, force) /* get lights for display object */
349     register DOBJECT *op;
350     int force;
351     {
352     double d2, mind2 = FHUGE*FHUGE;
353     FVECT ocent;
354     VIEW cvw;
355     register DLIGHTS *dl;
356    
357     op->ol = NULL;
358     if (op->drawcode != DO_LIGHT)
359     return(0);
360     /* check for usable light set */
361 gwlarson 3.2 getdcent(ocent, op);
362 gwlarson 3.1 for (dl = dlightsets; dl != NULL; dl = dl->next)
363     if ((d2 = dist2(dl->lcent, ocent)) < mind2) {
364     op->ol = dl;
365     mind2 = d2;
366     }
367     /* the following is heuristic */
368 gwlarson 3.2 d2 = 2.*getdrad(op); d2 *= d2;
369 gwlarson 3.1 if ((dl = op->ol) != NULL && (mind2 < 0.0625*dl->ravg*dl->ravg ||
370 gwlarson 3.2 mind2 < 4.*getdrad(op)*getdrad(op)))
371 gwlarson 3.1 return(1);
372     if (!force)
373     return(0);
374     /* need to compute new light set */
375     copystruct(&cvw, &stdview);
376     cvw.type = VT_PER;
377     VCOPY(cvw.vp, ocent);
378     cvw.vup[0] = 1.; cvw.vup[1] = cvw.vup[2] = 0.;
379     cvw.horiz = 90; cvw.vert = 90.;
380     beam_init(1); /* query beams through center */
381     cvw.vdir[0] = cvw.vdir[1] = 0.; cvw.vdir[2] = 1.;
382     setview(&cvw); beam_view(&cvw, 0, 0);
383     cvw.vdir[0] = cvw.vdir[1] = 0.; cvw.vdir[2] = -1.;
384     setview(&cvw); beam_view(&cvw, 0, 0);
385     cvw.vup[0] = cvw.vup[1] = 0.; cvw.vup[2] = 1.;
386     cvw.vdir[0] = cvw.vdir[2] = 0.; cvw.vdir[1] = 1.;
387     setview(&cvw); beam_view(&cvw, 0, 0);
388     cvw.vdir[0] = cvw.vdir[2] = 0.; cvw.vdir[1] = -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     cvw.vdir[1] = cvw.vdir[2] = 0.; cvw.vdir[0] = -1.;
393     setview(&cvw); beam_view(&cvw, 0, 0);
394     /* allocate new light set */
395     dl = (DLIGHTS *)calloc(1, sizeof(DLIGHTS));
396     if (dl == NULL)
397     goto memerr;
398     VCOPY(dl->lcent, ocent);
399     /* push onto our light set list */
400     dl->next = dlightsets;
401     dlightsets = dl;
402     dobj_lightsamp = ssph_sample; /* get beams from server */
403     imm_mode = beam_sync(-1) > 0;
404     while (imm_mode)
405     if (serv_result() == DS_SHUTDOWN)
406     quit(0);
407     if (!ssph_compute()) { /* compute light sources from sphere */
408     dlightsets = dl->next;
409     free((char *)dl);
410     return(0);
411     }
412     op->ol = dl;
413     return(1);
414     memerr:
415     error(SYSTEM, "out of memory in getdlights");
416     }
417    
418    
419     static int
420     cmderror(cn, err) /* report command error */
421     int cn;
422     char *err;
423     {
424     sprintf(errmsg, "%s: %s", rhdcmd[cn], err);
425     error(COMMAND, errmsg);
426     return(cn);
427     }
428    
429    
430     int
431     dobj_command(cmd, args) /* run object display command */
432     char *cmd;
433     register char *args;
434     {
435     int cn, na, doxfm;
436     register int nn;
437     char *alist[MAXAC+1], *nm;
438     /* find command */
439     for (cn = 0; cn < DO_NCMDS; cn++)
440     if (!strcmp(cmd, rhdcmd[cn]))
441     break;
442     if (cn >= DO_NCMDS)
443     return(-1); /* not in our list */
444     /* make argument list */
445     for (na = 0; *args; na++) {
446     if (na > MAXAC)
447     goto toomany;
448     alist[na] = args;
449     while (*args && !isspace(*args))
450     args++;
451     while (isspace(*args))
452     *args++ = '\0';
453     }
454     alist[na] = NULL;
455     /* execute command */
456     switch (cn) {
457     case DO_LOAD: /* load an octree */
458     if (na == 1)
459     dobj_load(alist[0], alist[0]);
460     else if (na == 2)
461     dobj_load(alist[0], alist[1]);
462     else
463     return(cmderror(cn, "need octree [name]"));
464     break;
465 gwlarson 3.5 case DO_UNLOAD: /* clear an object */
466 gwlarson 3.1 if (na > 1) goto toomany;
467     if (na && alist[0][0] == '*')
468     dobj_cleanup();
469     else
470     dobj_unload(na ? alist[0] : curname);
471     break;
472     case DO_XFORM: /* transform object */
473     case DO_MOVE:
474     if (na && alist[0][0] != '-') {
475     nm = alist[0]; nn = 1;
476     } else {
477     nm = curname; nn = 0;
478     }
479     if (cn == DO_MOVE && nn >= na)
480     return(cmderror(cn, "missing transform"));
481     dobj_xform(nm, cn==DO_MOVE, na-nn, alist+nn);
482     break;
483     case DO_UNMOVE: /* undo last transform */
484     dobj_unmove();
485     break;
486     case DO_OBJECT: /* print object statistics */
487 gwlarson 3.3 if (dobj_putstats(na ? alist[0] : curname, sstdout))
488 gwlarson 3.5 if (na && alist[0][0] != '*' && (curobj == NULL ||
489     strcmp(alist[0], curobj->name)))
490 gwlarson 3.3 savedxf(curobj = getdobj(alist[0]));
491 gwlarson 3.1 break;
492     case DO_DUP: /* duplicate object */
493     for (nn = 0; nn < na; nn++)
494     if (alist[nn][0] == '-')
495     break;
496     switch (nn) {
497     case 0:
498     return(cmderror(cn, "need new object name"));
499     case 1:
500     nm = curname;
501     break;
502     case 2:
503     nm = alist[0];
504     break;
505     default:
506     goto toomany;
507     }
508     if (!dobj_dup(nm, alist[nn-1]))
509     break;
510     if (na > nn)
511     dobj_xform(curname, 1, na-nn, alist+nn);
512     else
513     curobj->drawcode = DO_HIDE;
514 gwlarson 3.3 savedxf(curobj);
515 gwlarson 3.1 break;
516     case DO_SHOW: /* change rendering option */
517     case DO_LIGHT:
518     case DO_HIDE:
519     if (na > 1) goto toomany;
520     dobj_lighting(na ? alist[0] : curname, cn);
521     break;
522     default:
523     error(CONSISTENCY, "bad command id in dobj_command");
524     }
525     dev_view(&odev.v); /* redraw */
526     return(cn);
527     toomany:
528     return(cmderror(cn, "too many arguments"));
529     }
530    
531    
532     dobj_load(oct, nam) /* create/load an octree object */
533     char *oct, *nam;
534     {
535     extern char *getlibpath(), *getpath();
536     char *fpp, fpath[128];
537     register DOBJECT *op;
538     /* check arguments */
539     if (oct == NULL) {
540     error(COMMAND, "missing octree");
541     return(0);
542     }
543     if (nam == NULL) {
544     error(COMMAND, "missing name");
545     return(0);
546     }
547     if (*nam == '*' | *nam == '-') {
548     error(COMMAND, "illegal name");
549     return(0);
550     }
551 gwlarson 3.3 if (getdobj(nam) != NULL) {
552 gwlarson 3.5 error(COMMAND, "name already taken (clear first)");
553 gwlarson 3.3 return(0);
554     }
555 gwlarson 3.1 /* get octree path */
556     if ((fpp = getpath(oct, getlibpath(), R_OK)) == NULL) {
557     sprintf(errmsg, "cannot find octree \"%s\"", oct);
558     error(COMMAND, errmsg);
559     return(0);
560     }
561     strcpy(fpath, fpp);
562     op = (DOBJECT *)malloc(sizeof(DOBJECT));
563     if (op == NULL)
564     error(SYSTEM, "out of memory in dobj_load");
565     /* set struct fields */
566     strcpy(op->name, nam);
567     op->ol = NULL;
568     op->drawcode = DO_HIDE;
569     setident4(op->xfb.f.xfm); op->xfb.f.sca = 1.;
570     setident4(op->xfb.b.xfm); op->xfb.b.sca = 1.;
571     op->xfav[op->xfac=0] = NULL;
572     /* load octree into display list */
573     dolights = 0;
574     op->listid = rgl_octlist(fpath, op->center, &op->radius);
575     /* start rtrace */
576     rtargv[RTARGC-1] = fpath;
577     rtargv[RTARGC] = NULL;
578     open_process(op->rtp, rtargv);
579     /* insert into main list */
580     op->next = dobjects;
581     curobj = dobjects = op;
582     savedxf(NULL);
583     return(1);
584     }
585    
586    
587     dobj_unload(nam) /* free the named object */
588     char *nam;
589     {
590     register DOBJECT *op;
591    
592     if ((op = getdobj(nam)) == NULL) {
593     error(COMMAND, "no object");
594     return(0);
595     }
596     freedobj(op);
597     savedxf(curobj = NULL);
598     return(1);
599     }
600    
601    
602     dobj_cleanup() /* free all resources */
603     {
604     register DLIGHTS *lp;
605    
606     while (dobjects != NULL)
607     freedobj(dobjects);
608     savedxf(curobj = NULL);
609     while ((lp = dlightsets) != NULL) {
610     dlightsets = lp->next;
611     free((char *)lp);
612     }
613     return(1);
614     }
615    
616    
617 gwlarson 3.6 dobj_xform(nam, rel, ac, av) /* set/add transform for nam */
618 gwlarson 3.1 char *nam;
619 gwlarson 3.6 int rel, ac;
620 gwlarson 3.1 char **av;
621     {
622     register DOBJECT *op;
623 gwlarson 3.6 FVECT cent;
624     double rad;
625     char scoord[16];
626     int i;
627 gwlarson 3.1
628     if ((op = getdobj(nam)) == NULL) {
629     error(COMMAND, "no object");
630     return(0);
631     }
632 gwlarson 3.6 if (rel)
633     rel = op->xfac + 8;
634     if (ac + rel > MAXAC) {
635 gwlarson 3.1 error(COMMAND, "too many transform arguments");
636     return(0);
637     }
638 gwlarson 3.6 savedxf(curobj = op); /* remember current transform */
639     if (rel && ac == 4 && !strcmp(av[0], "-t"))
640     rel = -1; /* don't move for translate */
641     else {
642     getdcent(cent, op); /* don't move if near orig. */
643     rad = getdrad(op);
644     if (DOT(cent,cent) < rad*rad)
645     rel = -1;
646     }
647     if (!rel) { /* remove old transform */
648 gwlarson 3.1 while (op->xfac)
649     freestr(op->xfav[--op->xfac]);
650 gwlarson 3.6 } else if (rel > 0) { /* relative move */
651     op->xfav[op->xfac++] = savestr("-t");
652     for (i = 0; i < 3; i++) {
653     sprintf(scoord, "%.4e", -cent[i]);
654     op->xfav[op->xfac++] = savestr(scoord);
655     }
656     }
657 gwlarson 3.1 while (ac--)
658     op->xfav[op->xfac++] = savestr(*av++);
659 gwlarson 3.6 if (rel > 0) { /* move back */
660     op->xfav[op->xfac++] = savestr("-t");
661     for (i = 0; i < 3; i++) {
662     sprintf(scoord, "%.4e", cent[i]);
663     op->xfav[op->xfac++] = savestr(scoord);
664     }
665     }
666 gwlarson 3.1 op->xfav[op->xfac] = NULL;
667     if (fullxf(&op->xfb, op->xfac, op->xfav) != op->xfac) {
668     error(COMMAND, "bad transform arguments");
669     dobj_unmove();
670     savedxf(op); /* save current transform instead */
671     return(0);
672     }
673     /* don't know local lights anymore */
674     getdlights(op, 0);
675     return(1);
676     }
677    
678    
679     dobj_putstats(nam, fp) /* put out statistics for nam */
680     char *nam;
681     FILE *fp;
682     {
683     FVECT ocent;
684     register DOBJECT *op;
685     register int i;
686    
687     if (nam == NULL) {
688     error(COMMAND, "no current object");
689     return(0);
690     }
691     if (nam[0] == '*') {
692     i = 0;
693     for (op = dobjects; op != NULL; op = op->next)
694     i += dobj_putstats(op->name, fp);
695     return(i);
696     }
697     if ((op = getdobj(nam)) == NULL) {
698     error(COMMAND, "unknown object");
699     return(0);
700     }
701 gwlarson 3.2 getdcent(ocent, op);
702 gwlarson 3.6 fprintf(fp, "%s: %s, center [%g %g %g], radius %g", op->name,
703 gwlarson 3.3 op->drawcode==DO_HIDE ? "hidden" :
704     op->drawcode==DO_LIGHT && op->ol!=NULL ? "lighted" :
705 gwlarson 3.1 "shown",
706 gwlarson 3.2 ocent[0],ocent[1],ocent[2], getdrad(op));
707 gwlarson 3.1 if (op->xfac)
708     fputs(", (xform", fp);
709     for (i = 0; i < op->xfac; i++) {
710     putc(' ', fp);
711     fputs(op->xfav[i], fp);
712     }
713     if (op->xfac)
714     fputc(')', fp);
715     fputc('\n', fp);
716     return(1);
717     }
718    
719    
720     dobj_unmove() /* undo last transform change */
721     {
722     int txfac;
723     char *txfav[MAXAC+1];
724    
725     if (curobj == NULL) {
726     error(COMMAND, "no current object");
727     return(0);
728     }
729     /* hold last transform */
730     bcopy((char *)lastxfav, (char *)txfav,
731     (txfac=lastxfac)*sizeof(char *));
732     /* save this transform */
733     bcopy((char *)curobj->xfav, (char *)lastxfav,
734     (lastxfac=curobj->xfac)*sizeof(char *));
735     /* copy back last transform */
736     bcopy((char *)txfav, (char *)curobj->xfav,
737     (curobj->xfac=txfac)*sizeof(char *));
738     /* set matrices */
739     fullxf(&curobj->xfb, curobj->xfac, curobj->xfav);
740     /* don't know local lights anymore */
741     getdlights(curobj, 0);
742     return(1);
743     }
744    
745    
746     dobj_dup(oldnm, nam) /* duplicate object oldnm as nam */
747     char *oldnm, *nam;
748     {
749     register DOBJECT *op, *opdup;
750     /* check arguments */
751     if ((op = getdobj(oldnm)) == NULL) {
752     error(COMMAND, "no object");
753     return(0);
754     }
755     if (nam == NULL) {
756     error(COMMAND, "missing name");
757     return(0);
758     }
759     if (*nam == '*' | *nam == '-') {
760     error(COMMAND, "illegal name");
761     return(0);
762     }
763 gwlarson 3.3 if (getdobj(nam) != NULL) {
764 gwlarson 3.5 error(COMMAND, "name already taken (clear first)");
765 gwlarson 3.3 return(0);
766     }
767 gwlarson 3.1 /* allocate and copy struct */
768     opdup = (DOBJECT *)malloc(sizeof(DOBJECT));
769     if (opdup == NULL)
770     error(SYSTEM, "out of memory in dobj_dup");
771     copystruct(opdup, op);
772     /* rename */
773     strcpy(opdup->name, nam);
774     /* get our own copy of transform */
775     for (opdup->xfac = 0; opdup->xfac < op->xfac; opdup->xfac++)
776     opdup->xfav[opdup->xfac] = savestr(op->xfav[opdup->xfac]);
777     opdup->xfav[opdup->xfac] = NULL;
778     /* insert it into our list */
779     opdup->next = dobjects;
780     curobj = dobjects = opdup;
781     return(1);
782     }
783    
784    
785     dobj_lighting(nam, cn) /* set up lighting for display object */
786     char *nam;
787     int cn;
788     {
789     int i, res[2];
790     VIEW *dv;
791     register DOBJECT *op;
792    
793     if (nam == NULL) {
794     error(COMMAND, "no current object");
795     return(0);
796     }
797     if (nam[0] == '*') {
798     for (op = dobjects; op != NULL; op = op->next)
799     if ((op->drawcode = cn) == DO_LIGHT)
800     getdlights(op, 1);
801     else
802     op->ol = NULL;
803     } else if ((op = getdobj(nam)) == NULL) {
804     error(COMMAND, "unknown object");
805     return(0);
806 gwlarson 3.4 } else if ((op->drawcode = cn) == DO_LIGHT) {
807     if (!getdlights(op, 1))
808     error(COMMAND, "insufficient samples to light object");
809     } else
810 gwlarson 3.1 op->ol = NULL;
811    
812     if (dobj_lightsamp != NULL) { /* restore beam set */
813     dobj_lightsamp = NULL;
814     beam_init(1);
815     for (i = 0; (dv = dev_auxview(i, res)) != NULL; i++)
816     beam_view(dv, res[0], res[1]);
817     beam_sync(1); /* update server */
818     }
819     }
820    
821    
822     double
823 gwlarson 3.2 dobj_trace(nm, rorg, rdir) /* check for ray intersection with object(s) */
824     char nm[];
825 gwlarson 3.1 FVECT rorg, rdir;
826     {
827     register DOBJECT *op;
828     FVECT xorg, xdir;
829 gwlarson 3.2 double darr[6];
830 gwlarson 3.3 /* check each visible object? */
831 gwlarson 3.2 if (nm == NULL || *nm == '*') {
832     double dist, mindist = 1.01*FHUGE;
833 gwlarson 3.3
834     if (nm != NULL) nm[0] = '\0';
835 gwlarson 3.2 for (op = dobjects; op != NULL; op = op->next) {
836     if (op->drawcode == DO_HIDE)
837     continue;
838     dist = dobj_trace(op->name, rorg, rdir);
839     if (dist < mindist) {
840 gwlarson 3.3 if (nm != NULL) strcpy(nm, op->name);
841     mindist = dist;
842 gwlarson 3.2 }
843 gwlarson 3.1 }
844 gwlarson 3.2 return(mindist);
845 gwlarson 3.1 }
846 gwlarson 3.2 /* else check particular object */
847     if ((op = getdobj(nm)) == NULL) {
848     error(COMMAND, "unknown object");
849     return(FHUGE);
850     }
851 gwlarson 3.3 if (op->xfac) { /* put ray in local coordinates */
852 gwlarson 3.2 multp3(xorg, rorg, op->xfb.b.xfm);
853     multv3(xdir, rdir, op->xfb.b.xfm);
854     VCOPY(darr, xorg); VCOPY(darr+3, xdir);
855     } else {
856     VCOPY(darr, rorg); VCOPY(darr+3, rdir);
857     }
858     /* trace it */
859     if (process(op->rtp, darr, darr, sizeof(double),
860     6*sizeof(double)) != sizeof(double))
861     error(SYSTEM, "rtrace communication error");
862     /* return distance */
863     if (darr[0] >= .99*FHUGE)
864     return(FHUGE);
865 gwlarson 3.3 return(darr[0]*op->xfb.f.sca);
866 gwlarson 3.1 }
867    
868    
869     dobj_render() /* render our objects in OpenGL */
870     {
871     GLboolean normalizing;
872     GLfloat vec[4];
873 gwlarson 3.2 FVECT v1;
874 gwlarson 3.1 register DOBJECT *op;
875     register int i;
876     /* anything to render? */
877     for (op = dobjects; op != NULL; op = op->next)
878     if (op->drawcode != DO_HIDE)
879     break;
880     if (op == NULL)
881     return(1);
882     /* set up general rendering params */
883     glGetBooleanv(GL_NORMALIZE, &normalizing);
884 gwlarson 3.4 glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT|GL_ENABLE_BIT|
885     GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT);
886 gwlarson 3.1 glDepthFunc(GL_LESS);
887     glEnable(GL_DEPTH_TEST);
888     glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
889     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
890     glShadeModel(GL_SMOOTH);
891     glFrontFace(GL_CCW);
892     glDisable(GL_CULL_FACE);
893     for (i = MAXLIGHTS; i--; )
894     glDisable(glightid[i]);
895     glEnable(GL_LIGHTING);
896     rgl_checkerr("setting rendering modes in dobj_render");
897     /* render each object */
898     for (op = dobjects; op != NULL; op = op->next) {
899     if (op->drawcode == DO_HIDE)
900     continue;
901     /* set up lighting */
902     if (op->drawcode == DO_LIGHT && op->ol != NULL) {
903     BYTE pval;
904     double expval, d;
905 gwlarson 3.2 /* use computed sources */
906 gwlarson 3.1 if (tmMapPixels(&pval, &op->ol->larb, TM_NOCHROM, 1)
907     != TM_E_OK)
908     error(CONSISTENCY, "dobj_render w/o tone map");
909     expval = pval * (WHTEFFICACY/256.) /
910     tmLuminance(op->ol->larb);
911     vec[0] = expval * colval(op->ol->lamb,RED);
912     vec[1] = expval * colval(op->ol->lamb,GRN);
913     vec[2] = expval * colval(op->ol->lamb,BLU);
914     vec[3] = 1.;
915     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
916     for (i = op->ol->nl; i--; ) {
917     VCOPY(vec, op->ol->li[i].direc);
918     vec[3] = 0.;
919     glLightfv(glightid[i], GL_POSITION, vec);
920     d = expval * op->ol->li[i].omega;
921     vec[0] = d * colval(op->ol->li[i].val,RED);
922     vec[1] = d * colval(op->ol->li[i].val,GRN);
923     vec[2] = d * colval(op->ol->li[i].val,BLU);
924     vec[3] = 1.;
925     glLightfv(glightid[i], GL_SPECULAR, vec);
926     glLightfv(glightid[i], GL_DIFFUSE, vec);
927     vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
928     glLightfv(glightid[i], GL_AMBIENT, vec);
929     glEnable(glightid[i]);
930     }
931 gwlarson 3.3 } else { /* fake lighting */
932 gwlarson 3.2 vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
933 gwlarson 3.1 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
934 gwlarson 3.2 getdcent(v1, op);
935     VSUB(v1, odev.v.vp, v1);
936     if (normalize(v1) <= getdrad(op)) {
937     vec[0] = -odev.v.vdir[0];
938     vec[1] = -odev.v.vdir[1];
939     vec[2] = -odev.v.vdir[2];
940     } else
941     VCOPY(vec, v1);
942     vec[3] = 0.;
943     glLightfv(GL_LIGHT0, GL_POSITION, vec);
944     vec[0] = vec[1] = vec[2] = .7; vec[3] = 1.;
945     glLightfv(GL_LIGHT0, GL_SPECULAR, vec);
946     glLightfv(GL_LIGHT0, GL_DIFFUSE, vec);
947     vec[0] = vec[1] = vec[2] = .3; vec[3] = 1.;
948     glLightfv(GL_LIGHT0, GL_AMBIENT, vec);
949     glEnable(GL_LIGHT0);
950 gwlarson 3.1 }
951     /* set up object transform */
952     if (op->xfac) {
953     if (!normalizing && op->xfb.f.sca < 1.-FTINY |
954     op->xfb.f.sca > 1.+FTINY)
955     glEnable(GL_NORMALIZE);
956     glMatrixMode(GL_MODELVIEW);
957     glPushMatrix();
958     /* matrix order works out to same */
959     #ifdef SMLFLT
960     glMultMatrixf((GLfloat *)op->xfb.f.xfm);
961     #else
962     glMultMatrixd((GLdouble *)op->xfb.f.xfm);
963     #endif
964     }
965     /* render the display list */
966     glCallList(op->listid);
967     /* restore matrix */
968     if (op->xfac) {
969     glMatrixMode(GL_MODELVIEW);
970     glPopMatrix();
971     if (!normalizing)
972     glDisable(GL_NORMALIZE);
973     }
974     /* restore lighting */
975     if (op->drawcode == DO_LIGHT && op->ol != NULL)
976     for (i = op->ol->nl; i--; )
977     glDisable(glightid[i]);
978 gwlarson 3.2 else
979     glDisable(GL_LIGHT0);
980 gwlarson 3.1 /* check errors */
981     }
982     glPopAttrib(); /* restore rendering params */
983 gwlarson 3.3 rgl_checkerr("rendering objects in dobj_render");
984 gwlarson 3.1 return(1);
985     }