ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhdisp2.c
Revision: 3.8
Committed: Tue Dec 2 15:02:37 1997 UTC (26 years, 5 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 3.7: +40 -0 lines
Log Message:
made beam list updating more efficient using DR_ADJSET request

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