ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.12
Committed: Tue May 13 17:58:33 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.11: +5 -6 lines
Log Message:
Changed (char *) casts for memory copies to (void *) and other fixes

File Contents

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