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

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rhdobj.c,v 3.12 2003/05/13 17:58:33 greg Exp $";
3 #endif
4 /*
5 * Routines for loading and displaying Radiance objects in rholo with GLX.
6 */
7
8 #include "radogl.h"
9 #include "tonemap.h"
10 #include "rhdisp.h"
11 #include "rhdriver.h"
12 #include "rhdobj.h"
13 #include "rtprocess.h"
14
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 #define MAXAC 512 /* maximum number of args */
24
25 #ifndef MINTHRESH
26 #define MINTHRESH 5.0 /* source threshold w.r.t. mean */
27 #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 RREAL radius; /* orig. object radius */
55 int listid; /* GL display list identifier */
56 int nlists; /* number of lists allocated */
57 SUBPROC rtp; /* associated rtrace process */
58 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 #define getdcent(c,op) multp3(c,(op)->center,(op)->xfb.f.xfm)
72 #define getdrad(op) ((op)->radius*(op)->xfb.f.sca)
73
74 #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 glDeleteLists(op->listid, op->nlists);
122 close_process(&(op->rtp));
123 }
124 while (op->xfac)
125 freestr(op->xfav[--op->xfac]);
126 free((void *)op);
127 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 ncells = 0;
285 goto done;
286 }
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 if (thresh <= FTINY) {
295 ncells = 0;
296 goto done;
297 }
298 /* avg. reflected brightness */
299 d = AVGREFL / (double)ncells;
300 scalecolor(csum, d);
301 if (tmCvColors(&dlightsets->larb, TM_NOCHROM, &csum, 1) != TM_E_OK)
302 error(CONSISTENCY, "tone mapping problem in ssph_compute");
303 /* 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 ls->omega += 1.;
323 addcolor(ls->val, ssamp[alt][azi].val);
324 /* remove from list */
325 setcolor(ssamp[alt][azi].val, 0., 0., 0.);
326 ssamp[alt][azi].nsamp = 0;
327 }
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 done: /* clear sphere sample array */
341 bzero((void *)ssamp, sizeof(ssamp));
342 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 getdcent(ocent, op);
361 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 d2 = 2.*getdrad(op); d2 *= d2;
368 if ((dl = op->ol) != NULL && (mind2 < 0.0625*dl->ravg*dl->ravg ||
369 mind2 < 4.*getdrad(op)*getdrad(op)))
370 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 free((void *)dl);
409 return(0);
410 }
411 op->ol = dl;
412 return(1);
413 memerr:
414 error(SYSTEM, "out of memory in getdlights");
415 }
416
417
418 static
419 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 int somechange = 0;
434 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 else {
462 cmderror(cn, "need octree [name]");
463 return(0);
464 }
465 break;
466 case DO_UNLOAD: /* clear an object */
467 if (na > 1) goto toomany;
468 if (na && alist[0][0] == '*')
469 somechange += dobj_cleanup();
470 else
471 somechange += dobj_unload(na ? alist[0] : curname);
472 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 if (cn == DO_MOVE && nn >= na) {
481 cmderror(cn, "missing transform");
482 return(0);
483 }
484 somechange += dobj_xform(nm, cn==DO_MOVE, na-nn, alist+nn);
485 break;
486 case DO_UNMOVE: /* undo last transform */
487 somechange += dobj_unmove();
488 break;
489 case DO_OBJECT: /* print object statistics */
490 if (dobj_putstats(na ? alist[0] : curname, sstdout))
491 if (na && alist[0][0] != '*' && (curobj == NULL ||
492 strcmp(alist[0], curobj->name)))
493 savedxf(curobj = getdobj(alist[0]));
494 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 cmderror(cn, "need new object name");
502 return(0);
503 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 somechange += dobj_xform(curname, 1, na-nn, alist+nn);
516 else
517 curobj->drawcode = DO_HIDE;
518 savedxf(curobj);
519 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 somechange++;
526 break;
527 default:
528 error(CONSISTENCY, "bad command id in dobj_command");
529 }
530 return(somechange);
531 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 if (getdobj(nam) != NULL) {
555 error(COMMAND, "name already taken (clear first)");
556 return(0);
557 }
558 /* get octree path */
559 if ((fpp = getpath(oct, getrlibpath(), R_OK)) == NULL) {
560 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 domats = 1;
578 op->listid = rgl_octlist(fpath, op->center, &op->radius, &op->nlists);
579 /* start rtrace */
580 rtargv[RTARGC-1] = fpath;
581 rtargv[RTARGC] = NULL;
582 open_process(&(op->rtp), rtargv);
583 /* 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 free((void *)lp);
616 }
617 return(1);
618 }
619
620
621 dobj_xform(nam, rel, ac, av) /* set/add transform for nam */
622 char *nam;
623 int rel, ac;
624 char **av;
625 {
626 register DOBJECT *op;
627 FVECT cent;
628 double rad;
629 char scoord[16];
630 int i;
631
632 if ((op = getdobj(nam)) == NULL) {
633 error(COMMAND, "no object");
634 return(0);
635 }
636 if (rel)
637 rel = op->xfac + 8;
638 if (ac + rel > MAXAC) {
639 error(COMMAND, "too many transform arguments");
640 return(0);
641 }
642 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 while (op->xfac)
653 freestr(op->xfav[--op->xfac]);
654 } 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 while (ac--)
662 op->xfav[op->xfac++] = savestr(*av++);
663 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 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 getdcent(ocent, op);
706 fprintf(fp, "%s: %s, center [%g %g %g], radius %g", op->name,
707 op->drawcode==DO_HIDE ? "hidden" :
708 op->drawcode==DO_LIGHT && op->ol!=NULL ? "lighted" :
709 "shown",
710 ocent[0],ocent[1],ocent[2], getdrad(op));
711 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 bcopy((void *)lastxfav, (void *)txfav,
735 (txfac=lastxfac)*sizeof(char *));
736 /* save this transform */
737 bcopy((void *)curobj->xfav, (void *)lastxfav,
738 (lastxfac=curobj->xfac)*sizeof(char *));
739 /* copy back last transform */
740 bcopy((void *)txfav, (void *)curobj->xfav,
741 (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 if (getdobj(nam) != NULL) {
768 error(COMMAND, "name already taken (clear first)");
769 return(0);
770 }
771 /* 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 } else if ((op->drawcode = cn) == DO_LIGHT) {
811 if (!getdlights(op, 1))
812 error(COMMAND, "insufficient samples to light object");
813 } else
814 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 dobj_trace(nm, rorg, rdir) /* check for ray intersection with object(s) */
828 char nm[];
829 FVECT rorg, rdir;
830 {
831 register DOBJECT *op;
832 FVECT xorg, xdir;
833 double darr[6];
834 /* check each visible object? */
835 if (nm == NULL || *nm == '*') {
836 double dist, mindist = 1.01*FHUGE;
837
838 if (nm != NULL) nm[0] = '\0';
839 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 if (nm != NULL) strcpy(nm, op->name);
845 mindist = dist;
846 }
847 }
848 return(mindist);
849 }
850 /* else check particular object */
851 if ((op = getdobj(nm)) == NULL) {
852 error(COMMAND, "unknown object");
853 return(FHUGE);
854 }
855 if (op->xfac) { /* put ray in local coordinates */
856 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 if (process(&(op->rtp), (char *)darr, (char *)darr, sizeof(double),
864 6*sizeof(double)) != sizeof(double))
865 error(SYSTEM, "rtrace communication error");
866 /* return distance */
867 if (darr[0] >= .99*FHUGE)
868 return(FHUGE);
869 return(darr[0]*op->xfb.f.sca);
870 }
871
872
873 int
874 dobj_render() /* render our objects in OpenGL */
875 {
876 int nrendered = 0;
877 GLboolean normalizing;
878 GLfloat vec[4];
879 FVECT v1;
880 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 return(0);
888 /* set up general rendering params */
889 glGetBooleanv(GL_NORMALIZE, &normalizing);
890 glPushAttrib(GL_LIGHTING_BIT|GL_TRANSFORM_BIT|GL_ENABLE_BIT|
891 GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_POLYGON_BIT);
892 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 /* use computed sources */
912 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 } else { /* fake lighting */
938 vec[0] = vec[1] = vec[2] = 0.; vec[3] = 1.;
939 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, vec);
940 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 }
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 nrendered++;
974 /* 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 else
986 glDisable(GL_LIGHT0);
987 /* check errors */
988 }
989 glPopAttrib(); /* restore rendering params */
990 rgl_checkerr("rendering objects in dobj_render");
991 return(nrendered);
992 }