ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.1
Committed: Wed Aug 19 17:45:24 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

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