ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdobj.c
Revision: 3.18
Committed: Fri Jan 7 20:33:02 2005 UTC (19 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad4R0, rad3R8, rad3R9
Changes since 3.17: +5 -4 lines
Log Message:
Modernized tone-mapping routines with structure pointer r.t. stack

File Contents

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