ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.12
Committed: Tue May 13 17:58:33 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.11: +5 -6 lines
Log Message:
Changed (char *) casts for memory copies to (void *) and other fixes

File Contents

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