ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.6
Committed: Fri Oct 9 17:34:00 1998 UTC (25 years, 6 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.5: +38 -9 lines
Log Message:
changed moved command to do rotations and scaling relative to object center

File Contents

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