ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdisp2.c
Revision: 3.5
Committed: Fri Nov 21 18:17:37 1997 UTC (26 years, 5 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 3.4: +41 -39 lines
Log Message:
added check for holodeck behind viewpoint for more robust beam selection

File Contents

# Content
1 /* Copyright (c) 1997 Silicon Graphics, Inc. */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ SGI";
5 #endif
6
7 /*
8 * Holodeck beam tracking for display process
9 */
10
11 #include "rholo.h"
12 #include "rhdisp.h"
13 #include "rhdriver.h"
14
15 extern GCOORD *getviewcells();
16
17 typedef struct {
18 int hd; /* holodeck section number (-1 if inactive) */
19 int i[3]; /* voxel index (may be outside section) */
20 } VOXL; /* a voxel */
21
22 static VOXL voxel[8] = { /* current voxel list */
23 {-1}, {-1}, {-1}, {-1},
24 {-1}, {-1}, {-1}, {-1}
25 };
26
27 #define CBEAMBLK 1024 /* cbeam allocation block size */
28
29 static struct beamcomp {
30 short wants; /* flags telling which voxels want us */
31 short hd; /* holodeck section number */
32 int bi; /* beam index */
33 } *cbeam = NULL; /* current beam list */
34
35 static int ncbeams = 0; /* number of sorted beams in cbeam */
36 static int xcbeams = 0; /* extra (unregistered) beams past ncbeams */
37 static int maxcbeam = 0; /* size of cbeam array */
38
39 struct cellact {
40 short vi; /* voxel index */
41 short add; /* zero means delete */
42 short rev; /* reverse ray direction? */
43 }; /* action for cell */
44
45 struct beamact {
46 struct cellact ca; /* cell action */
47 GCOORD gc; /* grid coordinate */
48 }; /* beam origin and action */
49
50
51 int
52 newcbeam() /* allocate new entry at end of cbeam array */
53 {
54 int i;
55
56 if ((i = ncbeams + xcbeams++) >= maxcbeam) { /* grow array */
57 maxcbeam += CBEAMBLK;
58 if (cbeam == NULL)
59 cbeam = (struct beamcomp *)malloc(
60 maxcbeam*sizeof(struct beamcomp) );
61 else
62 cbeam = (struct beamcomp *)realloc( (char *)cbeam,
63 maxcbeam*sizeof(struct beamcomp) );
64 if (cbeam == NULL)
65 error(SYSTEM, "out of memory in newcbeam");
66 }
67 return(i);
68 }
69
70
71 int
72 cbeamcmp(cb1, cb2) /* compare two cbeam entries for sort: keep orphans */
73 register struct beamcomp *cb1, *cb2;
74 {
75 register int c;
76
77 if ((c = cb1->bi - cb2->bi)) /* sort on beam index first */
78 return(c);
79 return(cb1->hd - cb2->hd); /* use hd to resolve matches */
80 }
81
82
83 int
84 cbeamcmp2(cb1, cb2) /* compare two cbeam entries for sort: no orphans */
85 register struct beamcomp *cb1, *cb2;
86 {
87 register int c;
88
89 if (!cb1->wants) /* put orphans at the end, unsorted */
90 return(cb2->wants);
91 if ((c = cb1->bi - cb2->bi)) /* sort on beam index first */
92 return(c);
93 return(cb1->hd - cb2->hd); /* use hd to resolve matches */
94 }
95
96
97 int
98 findcbeam(hd, bi) /* find the specified beam in our sorted list */
99 int hd, bi;
100 {
101 struct beamcomp cb;
102 register struct beamcomp *p;
103
104 if (ncbeams <= 0)
105 return(-1);
106 cb.wants = 0; cb.hd = hd; cb.bi = bi;
107 p = (struct beamcomp *)bsearch((char *)&cb, (char *)cbeam, ncbeams,
108 sizeof(struct beamcomp), cbeamcmp);
109 if (p == NULL)
110 return(-1);
111 return(p - cbeam);
112 }
113
114
115 int
116 getcbeam(hd, bi) /* get the specified beam, allocating as necessary */
117 register int hd;
118 int bi;
119 {
120 register int n;
121 /* first, look in sorted list */
122 if ((n = findcbeam(hd, bi)) >= 0)
123 return(n);
124 /* linear search through xcbeams to be sure */
125 for (n = ncbeams+xcbeams; n-- > ncbeams; )
126 if (cbeam[n].bi == bi && cbeam[n].hd == hd)
127 return(n);
128 /* check legality */
129 if (hd < 0 | hd >= HDMAX || hdlist[hd] == NULL)
130 error(INTERNAL, "illegal holodeck number in getcbeam");
131 if (bi < 1 | bi > nbeams(hdlist[hd]))
132 error(INTERNAL, "illegal beam index in getcbeam");
133 n = newcbeam(); /* allocate and assign */
134 cbeam[n].wants = 0; cbeam[n].hd = hd; cbeam[n].bi = bi;
135 return(n);
136 }
137
138
139 cbeamsort(adopt) /* sort our beam list, possibly turning out orphans */
140 int adopt;
141 {
142 register int i;
143
144 if (!(ncbeams += xcbeams))
145 return;
146 xcbeams = 0;
147 qsort((char *)cbeam, ncbeams, sizeof(struct beamcomp),
148 adopt ? cbeamcmp : cbeamcmp2);
149 if (adopt)
150 return;
151 for (i = ncbeams; i--; ) /* identify orphans */
152 if (cbeam[i].wants)
153 break;
154 xcbeams = ncbeams - ++i; /* put orphans after ncbeams */
155 ncbeams = i;
156 }
157
158
159 cbeamop(op, bl, n, v, hr, vr) /* update beams on server list */
160 int op;
161 register struct beamcomp *bl;
162 int n;
163 VIEW *v;
164 int hr, vr;
165 {
166 register PACKHEAD *pa;
167 register int i;
168
169 if (n <= 0)
170 return;
171 pa = (PACKHEAD *)malloc(n*sizeof(PACKHEAD));
172 if (pa == NULL)
173 error(SYSTEM, "out of memory in cbeamadd");
174 for (i = 0; i < n; i++) {
175 pa[i].hd = bl[i].hd;
176 pa[i].bi = bl[i].bi;
177 pa[i].nr = v==NULL ? 0 :
178 npixels(v, hr, vr, hdlist[bl[i].hd], bl[i].bi);
179 }
180 serv_request(op, n*sizeof(PACKHEAD), (char *)pa);
181 free((char *)pa);
182 }
183
184
185 int
186 set_voxels(vl, n) /* set new voxel array */
187 VOXL vl[8];
188 int n;
189 {
190 short wmap[256];
191 int vmap[8];
192 int comn = 0;
193 int no;
194 register int i, j;
195 /* find common voxels */
196 for (j = 0; j < 8 && voxel[j].hd >= 0; j++) {
197 vmap[j] = -1;
198 for (i = n; i--; )
199 if (!bcmp((char *)(vl+i), (char *)(voxel+j),
200 sizeof(VOXL))) {
201 vmap[j] = i;
202 comn |= 1<<i;
203 break;
204 }
205 }
206 no = comn ? j : 0; /* compute flag mapping */
207 for (i = 256; i--; ) {
208 wmap[i] = 0;
209 for (j = no; j--; )
210 if (vmap[j] >= 0 && i & 1<<j)
211 wmap[i] |= 1<<vmap[j];
212 }
213 /* fix cbeam flags */
214 for (i = ncbeams; i--; )
215 cbeam[i].wants = wmap[cbeam[i].wants];
216 /* update our voxel list */
217 bcopy((char *)vl, (char *)voxel, n*sizeof(VOXL));
218 for (j = n; j < 8; j++)
219 voxel[j].hd = -1;
220 return(comn); /* return bit array of common voxels */
221 }
222
223
224 int
225 get_voxels(vl, vp) /* find voxels corresponding to view point */
226 VOXL vl[8];
227 FVECT vp;
228 {
229 static int lastn = 0, lastd = -1;
230 int n = 0;
231 FVECT gp;
232 double d;
233 int dist, bestd = 0x7fff;
234 VOXL vox;
235 register int i, j, k;
236 /* find closest voxels */
237 for (i = 0; n < 8 && hdlist[i]; i++) {
238 hdgrid(gp, hdlist[i], vp);
239 for (j = 0; n < 8 && j < 8; j++) {
240 dist = 0;
241 for (k = 0; k < 3; k++) {
242 d = gp[k] - .5 + (j>>k & 1);
243 if (d < 0.)
244 dist += -(vox.i[k] = (int)d - 1);
245 else if ((vox.i[k] = d) >= hdlist[i]->grid[k])
246 dist += vox.i[k] -
247 hdlist[i]->grid[k] + 1;
248 }
249 if (dist > bestd) /* others were closer */
250 continue;
251 if (dist < bestd) { /* start closer list */
252 n = 0;
253 bestd = dist;
254 }
255 vox.hd = i; /* add this voxel */
256 copystruct(&vl[n], &vox);
257 n++;
258 }
259 }
260 /* warn of dangerous moves */
261 if (n < lastn && bestd >= lastd)
262 error(WARNING, "moving outside holodeck section");
263 else if (n > lastn && bestd <= lastd)
264 error(WARNING, "moving inside holodeck section");
265 lastd = bestd;
266 return(lastn = n);
267 }
268
269
270 int
271 dobeam(gcp, bp) /* express interest or disintrest in a beam */
272 GCOORD *gcp;
273 register struct beamact *bp;
274 {
275 GCOORD gc[2];
276 int bi, i;
277 /* compute beam index */
278 if (bp->ca.rev) {
279 copystruct(gc, &bp->gc);
280 copystruct(gc+1, gcp);
281 } else {
282 copystruct(gc, gcp);
283 copystruct(gc+1, &bp->gc);
284 }
285 if ((bi = hdbindex(hdlist[voxel[bp->ca.vi].hd], gc)) <= 0)
286 error(CONSISTENCY, "bad grid coordinate in dobeam");
287 if (bp->ca.add) { /* add it in */
288 i = getcbeam(voxel[bp->ca.vi].hd, bi);
289 cbeam[i].wants |= 1<<bp->ca.vi; /* say we want it */
290 return(i == ncbeams+xcbeams-1); /* return 1 if totally new */
291 }
292 /* else delete it */
293 i = findcbeam(voxel[bp->ca.vi].hd, bi);
294 if (i >= 0 && cbeam[i].wants & 1<<bp->ca.vi) {
295 cbeam[i].wants &= ~(1<<bp->ca.vi); /* we don't want it */
296 return(1); /* indicate change */
297 }
298 return(0);
299 }
300
301
302
303 int
304 docell(gcp, cap) /* find beams corresponding to cell and voxel */
305 GCOORD *gcp;
306 register struct cellact *cap;
307 {
308 FVECT org, dir[4];
309 FVECT gp, cv[4], vc;
310 struct beamact bo;
311 register int i;
312 /* compute cell vertices */
313 hdcell(cv, hdlist[voxel[cap->vi].hd], gcp);
314 /* compute cell and voxel centers */
315 for (i = 0; i < 3; i++) {
316 org[i] = 0.5*(cv[0][i] + cv[2][i]);
317 gp[i] = voxel[cap->vi].i[i] + 0.5;
318 }
319 hdworld(vc, hdlist[voxel[cap->vi].hd], gp);
320 /* compute voxel pyramid using vector trick */
321 for (i = 0; i < 3; i++) {
322 dir[0][i] = vc[i] - cv[0][i]; /* to 3 */
323 dir[2][i] = vc[i] - cv[3][i]; /* to 0 */
324 if (gcp->w & 1) { /* watch vertex order! */
325 dir[1][i] = vc[i] - cv[2][i]; /* to 1 */
326 dir[3][i] = vc[i] - cv[1][i]; /* to 2 */
327 } else {
328 dir[1][i] = vc[i] - cv[1][i]; /* to 2 */
329 dir[3][i] = vc[i] - cv[2][i]; /* to 1 */
330 }
331 }
332 /* visit beams for opposite cells */
333 copystruct(&bo.ca, cap);
334 copystruct(&bo.gc, gcp);
335 return(visit_cells(org, dir, hdlist[voxel[cap->vi].hd], dobeam, &bo));
336 }
337
338
339 int
340 doview(cap, vp) /* visit cells for a given view */
341 struct cellact *cap;
342 VIEW *vp;
343 {
344 int orient;
345 FVECT org, dir[4];
346 /* compute view pyramid */
347 orient = viewpyramid(org, dir, hdlist[voxel[cap->vi].hd], vp);
348 if (!orient)
349 error(INTERNAL, "unusable view in doview");
350 cap->rev = orient < 0;
351 /* visit cells within pyramid */
352 return(visit_cells(org, dir, hdlist[voxel[cap->vi].hd], docell, cap));
353 }
354
355
356 mvview(voxi, vold, vnew) /* move view for a voxel */
357 int voxi;
358 VIEW *vold, *vnew;
359 {
360 int netchange = 0;
361 struct cellact oca, nca;
362 int ocnt, ncnt;
363 int c;
364 register GCOORD *ogcp, *ngcp;
365 /* get old and new cell lists */
366 ogcp = getviewcells(&ocnt, hdlist[voxel[voxi].hd], vold);
367 ngcp = getviewcells(&ncnt, hdlist[voxel[voxi].hd], vnew);
368 /* set up actions */
369 oca.vi = nca.vi = voxi;
370 oca.rev = nca.rev = 0;
371 oca.add = 0; nca.add = 1;
372 if ((oca.rev = ocnt < 0))
373 ocnt = -ocnt;
374 if ((nca.rev = ncnt < 0))
375 ncnt = -ncnt;
376 /* add and delete cells in order */
377 while (ocnt > 0 & ncnt > 0)
378 if ((c = cellcmp(ogcp, ngcp)) > 0) { /* new cell */
379 netchange += docell(ngcp++, &nca);
380 ncnt--;
381 } else if (c < 0) { /* obsolete cell */
382 netchange -= docell(ogcp++, &oca);
383 ocnt--;
384 } else { /* same cell? */
385 if (oca.rev != nca.rev) /* not */
386 netchange += docell(ngcp, &nca) -
387 docell(ogcp, &oca);
388 ogcp++; ocnt--;
389 ngcp++; ncnt--;
390 }
391 /* take care of list tails */
392 for ( ; ncnt > 0; ncnt--)
393 netchange += docell(ngcp++, &nca);
394 for ( ; ocnt > 0; ocnt--)
395 netchange -= docell(ogcp++, &oca);
396 /* clean up */
397 if (ogcp != NULL) free((char *)ogcp);
398 if (ngcp != NULL) free((char *)ngcp);
399 return(netchange);
400 }
401
402
403 beam_sync() /* synchronize beams on server */
404 {
405 cbeamop(DR_NEWSET, cbeam, ncbeams, &odev.v, odev.hres, odev.vres);
406 }
407
408
409 beam_view(vo, vn) /* change beam view */
410 VIEW *vo, *vn;
411 {
412 struct cellact ca;
413 VOXL vlnew[8];
414 int n, comn;
415
416 if (!vn->type) { /* clear our beam list */
417 set_voxels(vlnew, 0);
418 cbeamop(DR_DELSET, cbeam, ncbeams, NULL, 0, 0);
419 ncbeams = 0;
420 return;
421 }
422 /* find our new voxels */
423 n = get_voxels(vlnew, vn->vp);
424 /* set the new voxels */
425 comn = set_voxels(vlnew, n);
426 if (!vo->type)
427 comn = 0;
428 ca.add = 1; /* update our beam list */
429 for (ca.vi = n; ca.vi--; )
430 if (comn & 1<<ca.vi) /* change which cells we see */
431 mvview(ca.vi, vo, vn);
432 else /* else add all new cells */
433 doview(&ca, vn);
434 /* inform server of new beams */
435 cbeamop(DR_ADDSET, cbeam+ncbeams, xcbeams, vn, odev.hres, odev.vres);
436 /* sort list to put orphans at end */
437 cbeamsort(0);
438 /* tell server to delete orphans */
439 cbeamop(DR_DELSET, cbeam+ncbeams, xcbeams, NULL, 0, 0);
440 xcbeams = 0; /* truncate our list */
441 }