ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.18
Committed: Fri Jan 7 20:33:02 2005 UTC (19 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad4R0, rad3R8, rad3R9
Changes since 3.17: +5 -4 lines
Log Message:
Modernized tone-mapping routines with structure pointer r.t. stack

File Contents

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