ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.10
Committed: Fri Jan 29 15:33:36 1999 UTC (25 years, 3 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.9: +3 -2 lines
Log Message:
added number of lists for proper list deallocation

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