ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.10
Committed: Fri Jan 29 15:33:36 1999 UTC (25 years, 2 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.9: +3 -2 lines
Log Message:
added number of lists for proper list deallocation

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