| 1 | gregl | 3.1 | #ifndef lint | 
| 2 | greg | 3.33 | static const char       RCSid[] = "$Id$"; | 
| 3 | gregl | 3.1 | #endif | 
| 4 |  |  | /* | 
| 5 | gregl | 3.2 | * Holodeck beam tracking for display process | 
| 6 | gregl | 3.1 | */ | 
| 7 |  |  |  | 
| 8 |  |  | #include "rholo.h" | 
| 9 |  |  | #include "rhdisp.h" | 
| 10 |  |  | #include "rhdriver.h" | 
| 11 |  |  |  | 
| 12 | gwlarson | 3.26 | #ifndef MEYERNG | 
| 13 | gwlarson | 3.30 | #define MEYERNG         0.2     /* target mean eye range (rel. to grid) */ | 
| 14 | gwlarson | 3.26 | #endif | 
| 15 | gwlarson | 3.20 |  | 
| 16 | gregl | 3.1 | #define CBEAMBLK        1024    /* cbeam allocation block size */ | 
| 17 |  |  |  | 
| 18 | gwlarson | 3.32 | static PACKHEAD *cbeam = NULL;  /* current beam list */ | 
| 19 | gregl | 3.1 | static int      ncbeams = 0;    /* number of sorted beams in cbeam */ | 
| 20 |  |  | static int      xcbeams = 0;    /* extra (unregistered) beams past ncbeams */ | 
| 21 |  |  | static int      maxcbeam = 0;   /* size of cbeam array */ | 
| 22 |  |  |  | 
| 23 | gwlarson | 3.32 | VIEWPOINT       cureye;         /* current eye position */ | 
| 24 | gregl | 3.1 |  | 
| 25 | gwlarson | 3.32 |  | 
| 26 | gregl | 3.1 | int | 
| 27 |  |  | newcbeam()              /* allocate new entry at end of cbeam array */ | 
| 28 |  |  | { | 
| 29 |  |  | int     i; | 
| 30 |  |  |  | 
| 31 |  |  | if ((i = ncbeams + xcbeams++) >= maxcbeam) {    /* grow array */ | 
| 32 |  |  | maxcbeam += CBEAMBLK; | 
| 33 |  |  | if (cbeam == NULL) | 
| 34 | gwlarson | 3.32 | cbeam = (PACKHEAD *)malloc( | 
| 35 |  |  | maxcbeam*sizeof(PACKHEAD) ); | 
| 36 | gregl | 3.1 | else | 
| 37 | gwlarson | 3.32 | cbeam = (PACKHEAD *)realloc( (char *)cbeam, | 
| 38 |  |  | maxcbeam*sizeof(PACKHEAD) ); | 
| 39 | gregl | 3.1 | if (cbeam == NULL) | 
| 40 |  |  | error(SYSTEM, "out of memory in newcbeam"); | 
| 41 |  |  | } | 
| 42 |  |  | return(i); | 
| 43 |  |  | } | 
| 44 |  |  |  | 
| 45 |  |  |  | 
| 46 |  |  | int | 
| 47 |  |  | cbeamcmp(cb1, cb2)      /* compare two cbeam entries for sort: keep orphans */ | 
| 48 | gwlarson | 3.32 | register PACKHEAD       *cb1, *cb2; | 
| 49 | gregl | 3.1 | { | 
| 50 |  |  | register int    c; | 
| 51 |  |  |  | 
| 52 |  |  | if ((c = cb1->bi - cb2->bi))    /* sort on beam index first */ | 
| 53 |  |  | return(c); | 
| 54 |  |  | return(cb1->hd - cb2->hd);      /* use hd to resolve matches */ | 
| 55 |  |  | } | 
| 56 |  |  |  | 
| 57 |  |  |  | 
| 58 |  |  | int | 
| 59 |  |  | cbeamcmp2(cb1, cb2)     /* compare two cbeam entries for sort: no orphans */ | 
| 60 | gwlarson | 3.32 | register PACKHEAD       *cb1, *cb2; | 
| 61 | gregl | 3.1 | { | 
| 62 |  |  | register int    c; | 
| 63 |  |  |  | 
| 64 | gwlarson | 3.22 | if (!cb1->nr)                   /* put orphans at the end, unsorted */ | 
| 65 |  |  | return(cb2->nr); | 
| 66 |  |  | if (!cb2->nr) | 
| 67 | gregl | 3.15 | return(-1); | 
| 68 | gregl | 3.1 | if ((c = cb1->bi - cb2->bi))    /* sort on beam index first */ | 
| 69 |  |  | return(c); | 
| 70 |  |  | return(cb1->hd - cb2->hd);      /* use hd to resolve matches */ | 
| 71 |  |  | } | 
| 72 |  |  |  | 
| 73 |  |  |  | 
| 74 |  |  | int | 
| 75 |  |  | findcbeam(hd, bi)       /* find the specified beam in our sorted list */ | 
| 76 |  |  | int     hd, bi; | 
| 77 |  |  | { | 
| 78 | gwlarson | 3.32 | PACKHEAD        cb; | 
| 79 |  |  | register PACKHEAD       *p; | 
| 80 | gregl | 3.1 |  | 
| 81 |  |  | if (ncbeams <= 0) | 
| 82 |  |  | return(-1); | 
| 83 | gwlarson | 3.32 | cb.hd = hd; cb.bi = bi; cb.nr = cb.nc = 0; | 
| 84 |  |  | p = (PACKHEAD *)bsearch((char *)&cb, (char *)cbeam, ncbeams, | 
| 85 |  |  | sizeof(PACKHEAD), cbeamcmp); | 
| 86 | gregl | 3.1 | if (p == NULL) | 
| 87 |  |  | return(-1); | 
| 88 |  |  | return(p - cbeam); | 
| 89 |  |  | } | 
| 90 |  |  |  | 
| 91 |  |  |  | 
| 92 |  |  | int | 
| 93 |  |  | getcbeam(hd, bi)        /* get the specified beam, allocating as necessary */ | 
| 94 |  |  | register int    hd; | 
| 95 |  |  | int     bi; | 
| 96 |  |  | { | 
| 97 |  |  | register int    n; | 
| 98 |  |  | /* first, look in sorted list */ | 
| 99 |  |  | if ((n = findcbeam(hd, bi)) >= 0) | 
| 100 |  |  | return(n); | 
| 101 |  |  | /* linear search through xcbeams to be sure */ | 
| 102 |  |  | for (n = ncbeams+xcbeams; n-- > ncbeams; ) | 
| 103 |  |  | if (cbeam[n].bi == bi && cbeam[n].hd == hd) | 
| 104 |  |  | return(n); | 
| 105 |  |  | /* check legality */ | 
| 106 |  |  | if (hd < 0 | hd >= HDMAX || hdlist[hd] == NULL) | 
| 107 |  |  | error(INTERNAL, "illegal holodeck number in getcbeam"); | 
| 108 |  |  | if (bi < 1 | bi > nbeams(hdlist[hd])) | 
| 109 |  |  | error(INTERNAL, "illegal beam index in getcbeam"); | 
| 110 |  |  | n = newcbeam();         /* allocate and assign */ | 
| 111 | gwlarson | 3.32 | cbeam[n].hd = hd; cbeam[n].bi = bi; cbeam[n].nr = cbeam[n].nc = 0; | 
| 112 | gregl | 3.1 | return(n); | 
| 113 |  |  | } | 
| 114 |  |  |  | 
| 115 |  |  |  | 
| 116 |  |  | cbeamsort(adopt)        /* sort our beam list, possibly turning out orphans */ | 
| 117 |  |  | int     adopt; | 
| 118 |  |  | { | 
| 119 |  |  | register int    i; | 
| 120 |  |  |  | 
| 121 |  |  | if (!(ncbeams += xcbeams)) | 
| 122 |  |  | return; | 
| 123 |  |  | xcbeams = 0; | 
| 124 | gwlarson | 3.32 | qsort((char *)cbeam, ncbeams, sizeof(PACKHEAD), | 
| 125 | gregl | 3.1 | adopt ? cbeamcmp : cbeamcmp2); | 
| 126 |  |  | if (adopt) | 
| 127 |  |  | return; | 
| 128 |  |  | for (i = ncbeams; i--; )        /* identify orphans */ | 
| 129 | gwlarson | 3.22 | if (cbeam[i].nr) | 
| 130 | gregl | 3.1 | break; | 
| 131 |  |  | xcbeams = ncbeams - ++i;        /* put orphans after ncbeams */ | 
| 132 |  |  | ncbeams = i; | 
| 133 |  |  | } | 
| 134 |  |  |  | 
| 135 |  |  |  | 
| 136 | gwlarson | 3.24 | beam_init(fresh)                /* clear beam list for new view(s) */ | 
| 137 |  |  | int     fresh; | 
| 138 | gregl | 3.1 | { | 
| 139 | gwlarson | 3.21 | register int    i; | 
| 140 | gwlarson | 3.24 |  | 
| 141 |  |  | if (fresh)                      /* discard old beams? */ | 
| 142 |  |  | ncbeams = xcbeams = 0; | 
| 143 |  |  | else                            /* else clear sample requests */ | 
| 144 |  |  | for (i = ncbeams+xcbeams; i--; ) | 
| 145 |  |  | cbeam[i].nr = 0; | 
| 146 | gwlarson | 3.26 | cureye.rng = 0.; | 
| 147 | gregl | 3.1 | } | 
| 148 |  |  |  | 
| 149 |  |  |  | 
| 150 | gwlarson | 3.32 | int2 * | 
| 151 | gwlarson | 3.21 | beam_view(vn, hr, vr)           /* add beam view (if advisable) */ | 
| 152 |  |  | VIEW    *vn; | 
| 153 |  |  | int     hr, vr; | 
| 154 | gregl | 3.4 | { | 
| 155 | gwlarson | 3.32 | int2    *slist; | 
| 156 |  |  | BEAMLIST        blist; | 
| 157 |  |  | double  eravg, d; | 
| 158 | gwlarson | 3.26 | register HOLO   *hp; | 
| 159 | gwlarson | 3.32 | register int    i, n; | 
| 160 |  |  | /* compute beams for view */ | 
| 161 |  |  | slist = viewbeams(vn, hr, vr, &blist); | 
| 162 |  |  | if (*slist < 0) { | 
| 163 |  |  | error(COMMAND, "no sections visible from this view"); | 
| 164 | gwlarson | 3.29 | return(NULL); | 
| 165 | gwlarson | 3.32 | } | 
| 166 | gwlarson | 3.30 | /* sort current beam list */ | 
| 167 | gwlarson | 3.21 | cbeamsort(1); | 
| 168 | gwlarson | 3.32 | /* add new beams to list */ | 
| 169 |  |  | for (i = blist.nb; i--; ) { | 
| 170 |  |  | n = getcbeam(blist.bl[i].hd, blist.bl[i].bi); | 
| 171 |  |  | if (blist.bl[i].nr > cbeam[n].nr) | 
| 172 |  |  | cbeam[n].nr = blist.bl[i].nr; | 
| 173 |  |  | } | 
| 174 | greg | 3.33 | free((void *)blist.bl);         /* free list */ | 
| 175 | gwlarson | 3.32 | if (MEYERNG <= FTINY) | 
| 176 |  |  | return(slist); | 
| 177 |  |  | /* compute average eye range */ | 
| 178 | gwlarson | 3.30 | eravg = 0.; | 
| 179 | gwlarson | 3.32 | for (n = 0; slist[n] >= 0; n++) { | 
| 180 |  |  | hp = hdlist[slist[n]]; | 
| 181 |  |  | eravg +=        MEYERNG/3. / VLEN(hp->wg[0]) + | 
| 182 | gwlarson | 3.30 | MEYERNG/3. / VLEN(hp->wg[1]) + | 
| 183 |  |  | MEYERNG/3. / VLEN(hp->wg[2]) ; | 
| 184 |  |  | } | 
| 185 |  |  | eravg /= (double)n; | 
| 186 | gwlarson | 3.26 | /* add to current eye position */ | 
| 187 |  |  | if (cureye.rng <= FTINY) { | 
| 188 |  |  | VCOPY(cureye.vpt, vn->vp); | 
| 189 | gwlarson | 3.30 | cureye.rng = eravg; | 
| 190 |  |  | } else if ((d = sqrt(dist2(vn->vp,cureye.vpt))) + eravg > cureye.rng) { | 
| 191 | gwlarson | 3.26 | for (i = 3; i--; ) | 
| 192 |  |  | cureye.vpt[i] = 0.5*(cureye.vpt[i] + vn->vp[i]); | 
| 193 | gwlarson | 3.30 | cureye.rng = 0.5*(cureye.rng + eravg + d); | 
| 194 | gwlarson | 3.26 | } | 
| 195 | gwlarson | 3.32 | return(slist); | 
| 196 | gregl | 3.4 | } | 
| 197 |  |  |  | 
| 198 |  |  |  | 
| 199 | gwlarson | 3.21 | int | 
| 200 |  |  | beam_sync(all)                  /* update beam list on server */ | 
| 201 |  |  | int     all; | 
| 202 | gregl | 3.1 | { | 
| 203 | gwlarson | 3.26 | /* set new eye position */ | 
| 204 |  |  | serv_request(DR_VIEWPOINT, sizeof(VIEWPOINT), (char *)&cureye); | 
| 205 | gwlarson | 3.24 | /* sort list (put orphans at end) */ | 
| 206 |  |  | cbeamsort(all < 0); | 
| 207 | gwlarson | 3.26 | /* send beam request */ | 
| 208 | gwlarson | 3.32 | if (all) { | 
| 209 |  |  | if (ncbeams > 0) | 
| 210 |  |  | serv_request(DR_NEWSET, | 
| 211 |  |  | ncbeams*sizeof(PACKHEAD), cbeam); | 
| 212 |  |  | } else { | 
| 213 |  |  | if (ncbeams+xcbeams > 0) | 
| 214 |  |  | serv_request(DR_ADJSET, | 
| 215 |  |  | (ncbeams+xcbeams)*sizeof(PACKHEAD), cbeam); | 
| 216 |  |  | } | 
| 217 | gregl | 3.1 | xcbeams = 0;                    /* truncate our list */ | 
| 218 | gwlarson | 3.21 | return(ncbeams); | 
| 219 | gwlarson | 3.32 | } | 
| 220 |  |  |  | 
| 221 |  |  |  | 
| 222 |  |  | gridlines(f)                    /* run through holodeck section grid lines */ | 
| 223 |  |  | int     (*f)(); | 
| 224 |  |  | { | 
| 225 |  |  | register int    hd, w, i; | 
| 226 |  |  | int     g0, g1; | 
| 227 |  |  | FVECT   wp[2], mov; | 
| 228 |  |  | double  d; | 
| 229 |  |  | /* do each wall on each section */ | 
| 230 |  |  | for (hd = 0; hdlist[hd] != NULL; hd++) | 
| 231 |  |  | for (w = 0; w < 6; w++) { | 
| 232 |  |  | g0 = hdwg0[w]; | 
| 233 |  |  | g1 = hdwg1[w]; | 
| 234 |  |  | d = 1.0/hdlist[hd]->grid[g0]; | 
| 235 |  |  | mov[0] = d * hdlist[hd]->xv[g0][0]; | 
| 236 |  |  | mov[1] = d * hdlist[hd]->xv[g0][1]; | 
| 237 |  |  | mov[2] = d * hdlist[hd]->xv[g0][2]; | 
| 238 |  |  | if (w & 1) { | 
| 239 |  |  | VSUM(wp[0], hdlist[hd]->orig, | 
| 240 |  |  | hdlist[hd]->xv[w>>1], 1.); | 
| 241 |  |  | VSUM(wp[0], wp[0], mov, 1.); | 
| 242 |  |  | } else | 
| 243 |  |  | VCOPY(wp[0], hdlist[hd]->orig); | 
| 244 |  |  | VSUM(wp[1], wp[0], hdlist[hd]->xv[g1], 1.); | 
| 245 |  |  | for (i = hdlist[hd]->grid[g0]; ; ) {    /* g0 lines */ | 
| 246 |  |  | (*f)(wp); | 
| 247 |  |  | if (!--i) break; | 
| 248 |  |  | wp[0][0] += mov[0]; wp[0][1] += mov[1]; | 
| 249 |  |  | wp[0][2] += mov[2]; wp[1][0] += mov[0]; | 
| 250 |  |  | wp[1][1] += mov[1]; wp[1][2] += mov[2]; | 
| 251 |  |  | } | 
| 252 |  |  | d = 1.0/hdlist[hd]->grid[g1]; | 
| 253 |  |  | mov[0] = d * hdlist[hd]->xv[g1][0]; | 
| 254 |  |  | mov[1] = d * hdlist[hd]->xv[g1][1]; | 
| 255 |  |  | mov[2] = d * hdlist[hd]->xv[g1][2]; | 
| 256 |  |  | if (w & 1) | 
| 257 |  |  | VSUM(wp[0], hdlist[hd]->orig, | 
| 258 |  |  | hdlist[hd]->xv[w>>1], 1.); | 
| 259 |  |  | else | 
| 260 |  |  | VSUM(wp[0], hdlist[hd]->orig, mov, 1.); | 
| 261 |  |  | VSUM(wp[1], wp[0], hdlist[hd]->xv[g0], 1.); | 
| 262 |  |  | for (i = hdlist[hd]->grid[g1]; ; ) {    /* g1 lines */ | 
| 263 |  |  | (*f)(wp); | 
| 264 |  |  | if (!--i) break; | 
| 265 |  |  | wp[0][0] += mov[0]; wp[0][1] += mov[1]; | 
| 266 |  |  | wp[0][2] += mov[2]; wp[1][0] += mov[0]; | 
| 267 |  |  | wp[1][1] += mov[1]; wp[1][2] += mov[2]; | 
| 268 |  |  | } | 
| 269 |  |  | } | 
| 270 | gregl | 3.1 | } |