ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.13
Committed: Thu Jun 26 00:58:10 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 3.12: +7 -6 lines
Log Message:
Abstracted process and path handling for Windows.
Renamed FLOAT to RREAL because of conflict on Windows.
Added conditional compiles for some signal handlers.

File Contents

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