|
|
1.1 ! root 1: /*% 3cc -c % ! 2: * Fixed-point 3d coordinate transform routines for machines with ! 3: * 16 bit shorts and 32 bit longs. ! 4: */ ! 5: #include <jerq.h> ! 6: #include <3d.h> ! 7: #include <font.h> ! 8: static Hcoordl cur; ! 9: static Point cen; ! 10: static int wid; ! 11: /* ! 12: * angles are scaled so that PI=>32768 ! 13: * Since unsigned shorts are 16 bits, 2*PI overflows and yields ! 14: * 0, which seems appropriate. ! 15: */ ! 16: angle cvtangle[361]={ ! 17: 0, 182, 364, 546, 728, 910, 1092, 1274, ! 18: 1456, 1638, 1820, 2002, 2184, 2366, 2548, 2730, ! 19: 2912, 3094, 3276, 3458, 3640, 3822, 4004, 4187, ! 20: 4369, 4551, 4733, 4915, 5097, 5279, 5461, 5643, ! 21: 5825, 6007, 6189, 6371, 6553, 6735, 6917, 7099, ! 22: 7281, 7463, 7645, 7827, 8009, 8192, 8374, 8556, ! 23: 8738, 8920, 9102, 9284, 9466, 9648, 9830, 10012, ! 24: 10194, 10376, 10558, 10740, 10922, 11104, 11286, 11468, ! 25: 11650, 11832, 12014, 12196, 12379, 12561, 12743, 12925, ! 26: 13107, 13289, 13471, 13653, 13835, 14017, 14199, 14381, ! 27: 14563, 14745, 14927, 15109, 15291, 15473, 15655, 15837, ! 28: 16019, 16201, 16384, 16566, 16748, 16930, 17112, 17294, ! 29: 17476, 17658, 17840, 18022, 18204, 18386, 18568, 18750, ! 30: 18932, 19114, 19296, 19478, 19660, 19842, 20024, 20206, ! 31: 20388, 20571, 20753, 20935, 21117, 21299, 21481, 21663, ! 32: 21845, 22027, 22209, 22391, 22573, 22755, 22937, 23119, ! 33: 23301, 23483, 23665, 23847, 24029, 24211, 24393, 24576, ! 34: 24758, 24940, 25122, 25304, 25486, 25668, 25850, 26032, ! 35: 26214, 26396, 26578, 26760, 26942, 27124, 27306, 27488, ! 36: 27670, 27852, 28034, 28216, 28398, 28580, 28763, 28945, ! 37: 29127, 29309, 29491, 29673, 29855, 30037, 30219, 30401, ! 38: 30583, 30765, 30947, 31129, 31311, 31493, 31675, 31857, ! 39: 32039, 32221, 32403, 32585, 32768, 32950, 33132, 33314, ! 40: 33496, 33678, 33860, 34042, 34224, 34406, 34588, 34770, ! 41: 34952, 35134, 35316, 35498, 35680, 35862, 36044, 36226, ! 42: 36408, 36590, 36772, 36955, 37137, 37319, 37501, 37683, ! 43: 37865, 38047, 38229, 38411, 38593, 38775, 38957, 39139, ! 44: 39321, 39503, 39685, 39867, 40049, 40231, 40413, 40595, ! 45: 40777, 40960, 41142, 41324, 41506, 41688, 41870, 42052, ! 46: 42234, 42416, 42598, 42780, 42962, 43144, 43326, 43508, ! 47: 43690, 43872, 44054, 44236, 44418, 44600, 44782, 44964, ! 48: 45147, 45329, 45511, 45693, 45875, 46057, 46239, 46421, ! 49: 46603, 46785, 46967, 47149, 47331, 47513, 47695, 47877, ! 50: 48059, 48241, 48423, 48605, 48787, 48969, 49152, 49334, ! 51: 49516, 49698, 49880, 50062, 50244, 50426, 50608, 50790, ! 52: 50972, 51154, 51336, 51518, 51700, 51882, 52064, 52246, ! 53: 52428, 52610, 52792, 52974, 53156, 53339, 53521, 53703, ! 54: 53885, 54067, 54249, 54431, 54613, 54795, 54977, 55159, ! 55: 55341, 55523, 55705, 55887, 56069, 56251, 56433, 56615, ! 56: 56797, 56979, 57161, 57344, 57526, 57708, 57890, 58072, ! 57: 58254, 58436, 58618, 58800, 58982, 59164, 59346, 59528, ! 58: 59710, 59892, 60074, 60256, 60438, 60620, 60802, 60984, ! 59: 61166, 61348, 61531, 61713, 61895, 62077, 62259, 62441, ! 60: 62623, 62805, 62987, 63169, 63351, 63533, 63715, 63897, ! 61: 64079, 64261, 64443, 64625, 64807, 64989, 65171, 65353, ! 62: 65536, ! 63: }; ! 64: static fract sintab[128+2]={ ! 65: 0, 201, 402, 603, 803, 1004, 1205, 1405, ! 66: 1605, 1805, 2005, 2204, 2404, 2602, 2801, 2998, ! 67: 3196, 3393, 3589, 3785, 3980, 4175, 4369, 4563, ! 68: 4756, 4948, 5139, 5329, 5519, 5708, 5896, 6083, ! 69: 6269, 6455, 6639, 6822, 7005, 7186, 7366, 7545, ! 70: 7723, 7900, 8075, 8249, 8423, 8594, 8765, 8934, ! 71: 9102, 9268, 9434, 9597, 9759, 9920, 10079, 10237, ! 72: 10393, 10548, 10701, 10853, 11002, 11150, 11297, 11442, ! 73: 11585, 11726, 11866, 12003, 12139, 12273, 12406, 12536, ! 74: 12665, 12791, 12916, 13038, 13159, 13278, 13395, 13510, ! 75: 13622, 13733, 13842, 13948, 14053, 14155, 14255, 14353, ! 76: 14449, 14543, 14634, 14723, 14810, 14895, 14978, 15058, ! 77: 15136, 15212, 15286, 15357, 15426, 15492, 15557, 15618, ! 78: 15678, 15735, 15790, 15842, 15892, 15940, 15985, 16028, ! 79: 16069, 16107, 16142, 16175, 16206, 16234, 16260, 16284, ! 80: 16305, 16323, 16339, 16353, 16364, 16372, 16379, 16382, ! 81: 16384, 16382, ! 82: }; ! 83: fract isin(x) ! 84: register angle x; ! 85: { ! 86: register fract a, b; ! 87: register i, f=0; ! 88: if(x>=PI){ ! 89: x-=PI; ! 90: f=1; ! 91: } ! 92: if(x>PI/2) ! 93: x=PI-x; ! 94: i=x>>7; ! 95: a=sintab[i]; ! 96: b=sintab[i+1]-a; ! 97: i=x&0177; ! 98: a+=(b*i+64)/128; ! 99: return(f?-a:a); ! 100: } ! 101: fract icos(x) ! 102: register angle x; ! 103: { ! 104: return(isin(x+PI/2)); ! 105: } ! 106: long isqrt(a) ! 107: register long a; ! 108: { ! 109: register long x, y; ! 110: if(a<=0)return(0); ! 111: for(y=a,x=1;y!=0;y>>=2,x<<=1); ! 112: while((y=(a/x+x)>>1)<x)x=y; ! 113: return(x); ! 114: } ! 115: #define NSTACK 32 ! 116: Hcoord hcoord(x, y, z, w) ! 117: fract x, y, z, w; ! 118: { ! 119: Hcoord r; ! 120: r.x=x; ! 121: r.y=y; ! 122: r.z=z; ! 123: r.w=w; ! 124: return(r); ! 125: } ! 126: matrix stack3[NSTACK]={ ! 127: ONE,0,0,0, ! 128: 0,ONE,0,0, ! 129: 0,0,ONE,0, ! 130: 0,0,0,ONE, ! 131: }; ! 132: matrix *sp3=stack3; /* matrix stack pointer */ ! 133: /* ! 134: * Initialize the matrix stack. ! 135: * v is the viewport into which to map the image. (d/s) is the distance to the ! 136: * screen, whose half-width is 1. (equivalently, d is the distance to a screen of ! 137: * half-size s.) ! 138: */ ! 139: Bitmap *viewport; ! 140: init3(v, d, s) ! 141: Bitmap *v; ! 142: { ! 143: sp3=stack3; ! 144: ident(*sp3); ! 145: (*sp3)[0][0]=(*sp3)[2][2]=d; ! 146: (*sp3)[1][1]=s; ! 147: (*sp3)[3][3]=s; ! 148: viewport=v; ! 149: cen=div(add(v->rect.origin, v->rect.corner), 2); ! 150: wid=min(v->rect.corner.x-v->rect.origin.x, ! 151: v->rect.corner.y-v->rect.origin.y)/2; ! 152: } ! 153: /* ! 154: * Push a copy of the top of the matrix stack onto the stack ! 155: */ ! 156: push3(){ ! 157: register i, j; ! 158: ;if(sp3==stack3+NSTACK-1) ! 159: return(-1); ! 160: for(i=0;i!=4;i++) for(j=0;j!=4;j++) ! 161: sp3[1][i][j]=sp3[0][i][j]; ! 162: sp3++; ! 163: return(0); ! 164: } ! 165: /* ! 166: * pop the top matrix off the stack ! 167: */ ! 168: pop3(){ ! 169: if(sp3==stack3) ! 170: return(-1); ! 171: --sp3; ! 172: return(0); ! 173: } ! 174: /* ! 175: * Multiply the top matrix on the stack by rotation of angle theta about ! 176: * the given axis. ! 177: */ ! 178: rot3(theta, axis) ! 179: angle theta; ! 180: { ! 181: rotsc3(isin(theta), icos(theta), axis); ! 182: } ! 183: /* ! 184: * rotate, given the sin and cosine of the rotation angle. ! 185: */ ! 186: rotsc3(s, c, axis) ! 187: short s, c; ! 188: { ! 189: matrix m; ! 190: register i=(axis+1)%3, j=(axis+2)%3; ! 191: ident(m); ! 192: m[i][i] = c; ! 193: m[i][j] = -s; ! 194: m[j][i] = s; ! 195: m[j][j] = c; ! 196: xform3(m); ! 197: } ! 198: /* ! 199: * Scale by a factor of [xyz]/w about axis [xyz] ! 200: */ ! 201: scale3(p) ! 202: Hcoord p; ! 203: { ! 204: matrix m; ! 205: ident(m); ! 206: m[0][0]=p.x; ! 207: m[1][1]=p.y; ! 208: m[2][2]=p.z; ! 209: m[3][3]=p.w; ! 210: xform3(m); ! 211: } ! 212: /* ! 213: * translate by (dx/dw, dy/dw, dz/dw) ! 214: */ ! 215: tran3(p) ! 216: Hcoord p; ! 217: { ! 218: matrix m; ! 219: ident(m); ! 220: m[0][0]=p.w; ! 221: m[1][1]=p.w; ! 222: m[2][2]=p.w; ! 223: m[3][3]=p.w; ! 224: m[0][3]=p.x; ! 225: m[1][3]=p.y; ! 226: m[2][3]=p.z; ! 227: xform3(m); ! 228: } ! 229: /* ! 230: * Store an identity matrix in m ! 231: */ ! 232: ident(m) ! 233: matrix m; ! 234: { ! 235: register fract *s = &m[0][0]; ! 236: *s++=ONE;*s++=0;*s++=0;*s++=0; ! 237: *s++=0;*s++=ONE;*s++=0;*s++=0; ! 238: *s++=0;*s++=0;*s++=ONE;*s++=0; ! 239: *s++=0;*s++=0;*s++=0;*s++=ONE; ! 240: } ! 241: /* ! 242: * Multiply the top of the matrix stack by m ! 243: */ ! 244: xform3(m) ! 245: matrix m; ! 246: { ! 247: register i, j, k; ! 248: long sum, max=0; ! 249: long tmp[4][4]; ! 250: char buf[128]; ! 251: ! 252: for(i=0;i!=4;i++) for(j=0;j!=4;j++){ ! 253: sum=0; ! 254: for(k=0;k!=4;k++) ! 255: sum+=(long)(*sp3)[i][k]*m[k][j]; ! 256: tmp[i][j]=sum; ! 257: if(sum<0) ! 258: sum = -sum; ! 259: if(sum>max) ! 260: max=sum; ! 261: } ! 262: if((k = max/(ONE-1)) == 0) k = 1; ! 263: for(i=0;i!=4;i++) for(j=0;j!=4;j++) ! 264: (*sp3)[i][j]=tmp[i][j]/k; ! 265: } ! 266: long dot(a, b) ! 267: Hcoord a, b; ! 268: { ! 269: return((long)a.x*b.x+(long)a.y*b.y+(long)a.z*b.z); ! 270: } ! 271: Hcoord unitize(a) ! 272: Hcoord a; ! 273: { ! 274: short l=isqrt(dot(a, a)); ! 275: Hcoord v; ! 276: if(l==0){ ! 277: v=a; ! 278: v.w=0; ! 279: } ! 280: else{ ! 281: if(a.w<0) l = -l; ! 282: v.x=muldiv(a.x, ONE, l); ! 283: v.y=muldiv(a.y, ONE, l); ! 284: v.z=muldiv(a.z, ONE, l); ! 285: v.w=ONE; ! 286: } ! 287: return(v); ! 288: } ! 289: Hcoord cross(a, b) ! 290: Hcoord a, b; ! 291: { ! 292: Hcoord r; ! 293: r.x=((long)a.y*b.z-(long)a.z*b.y)/ONE; ! 294: r.y=((long)a.z*b.x-(long)a.x*b.z)/ONE; ! 295: r.z=((long)a.x*b.y-(long)a.y*b.x)/ONE; ! 296: r.w=ONE; ! 297: return(r); ! 298: } ! 299: /* ! 300: * multiply the top of the maxrix stack by a view-pointing transformation ! 301: * with the eyepoint at e, looking in direction (lx, ly, lz), ! 302: * with up direction (ux, uy, uz) ! 303: */ ! 304: look3(e, l, u) ! 305: Hcoord e, l, u; ! 306: { ! 307: matrix m; ! 308: fract len; ! 309: Hcoord r; ! 310: ! 311: /*printf("look3(e=(%d,%d,%d,%d), l=(%d,%d,%d,%d), u=(%d,%d,%d,%d))\n", ! 312: e.x,e.y,e.z,e.w,l.x,l.y,l.z,l.w,u.x,u.y,u.z,u.w);*/ ! 313: l=unitize(l); ! 314: if(l.w==0){ ! 315: l.y=ONE; ! 316: l.w=ONE; ! 317: } ! 318: /* Adjust u to be perpendicular to l */ ! 319: u=unitize(u); ! 320: len=dot(u, l)/ONE; ! 321: u.x-=muldiv(len, l.x, ONE); ! 322: u.y-=muldiv(len, l.y, ONE); ! 323: u.z-=muldiv(len, l.z, ONE); ! 324: u=unitize(u); ! 325: if(u.w==0){ ! 326: u.z=ONE; ! 327: u.w=ONE; ! 328: } ! 329: r=cross(l, u); ! 330: /*printf("r=(%d,%d,%d,%d), l=(%d,%d,%d,%d), u=(%d,%d,%d,%d))\n", ! 331: r.x,r.y,r.z,r.w,l.x,l.y,l.z,l.w,u.x,u.y,u.z,u.w);*/ ! 332: /* make the matrix to transform from (rlu) space to (xyz) space */ ! 333: ident(m); ! 334: m[0][0]=r.x; m[0][1]=r.y; m[0][2]=r.z; ! 335: m[1][0]=l.x; m[1][1]=l.y; m[1][2]=l.z; ! 336: m[2][0]=u.x; m[2][1]=u.y; m[2][2]=u.z; ! 337: xform3(m); ! 338: tran3(hcoord(e.x, e.y, e.z, -e.w)); ! 339: } ! 340: Hcoordl xformp(p) ! 341: Hcoord p; ! 342: { ! 343: Hcoordl r; ! 344: r.x=(long)(*sp3)[0][0]*p.x+(long)(*sp3)[0][1]*p.y ! 345: +(long)(*sp3)[0][2]*p.z+(long)(*sp3)[0][3]*p.w; ! 346: r.y=(long)(*sp3)[1][0]*p.x+(long)(*sp3)[1][1]*p.y ! 347: +(long)(*sp3)[1][2]*p.z+(long)(*sp3)[1][3]*p.w; ! 348: r.z=(long)(*sp3)[2][0]*p.x+(long)(*sp3)[2][1]*p.y ! 349: +(long)(*sp3)[2][2]*p.z+(long)(*sp3)[2][3]*p.w; ! 350: r.w=(long)(*sp3)[3][0]*p.x+(long)(*sp3)[3][1]*p.y ! 351: +(long)(*sp3)[3][2]*p.z+(long)(*sp3)[3][3]*p.w; ! 352: return(r); ! 353: } ! 354: move3(p) ! 355: Hcoord p; ! 356: { ! 357: cur=xformp(p); ! 358: /*printf("move3(%d,%d,%d,%d)\n", p.x, p.y, p.z, p.w);*/ ! 359: } ! 360: line3(p) ! 361: Hcoord p; ! 362: { ! 363: Hcoordl new; ! 364: /*printf("line3(%d,%d,%d,%d)\n", p.x, p.y, p.z, p.w);*/ ! 365: new=xformp(p); ! 366: clipanddraw(cur, new); ! 367: cur=new; ! 368: } ! 369: /* ! 370: * clip points to the viewing volume, then do perspective division ! 371: * and mapping to screen coordinates and draw lines. We only clip against the ! 372: * eye plane, trusting segment to clip in x and z. There probably should ! 373: * be some overflow precaution taken in the multiplication by n/d. ! 374: */ ! 375: int clip3scale = 0; ! 376: ! 377: static clipanddraw(a, b) ! 378: Hcoordl a, b; ! 379: { ! 380: Point A, B; ! 381: Hcoordl t; ! 382: int clip=0; ! 383: long n, d; ! 384: long m; ! 385: long as, bs; ! 386: #define OV (32767) /* 2**(15.5) */ ! 387: /* ! 388: * we clip against the plane p=(0,1,0,-1) [this corresponds ! 389: * to the euclidean plane y=1. This is picked rather than y=0 ! 390: * to avoid a divide check in the perspective divide] ! 391: * First we check to see if one endpoint is on each side of the plane. ! 392: * and if necessary switch them so that a is behind and b is in front. ! 393: * then we replace a by a+(b-a)*n/d, where p.(a+(b-a)*n/d)=0 ! 394: * i.e. a.y+(b.y-a.y)*n/d-a.w-(b.w-a.w)*n/d=0 ! 395: * (b.y-a.y-b.w+a.w)*n/d=a.w-a.y ! 396: * n/d=(a.w-a.y)/(b.y-a.y-b.w+a.w) ! 397: */ ! 398: /*printf("clipanddraw(a=(%d,%d,%d,%d), b=(%d,%d,%d,%d)\n", ! 399: a.x,a.y,a.z,a.w,b.x,b.y,b.z,b.w);*/ ! 400: if(a.w>0?a.y<a.w:a.y>a.w) /* eqv. a.y/a.w<1, but avoids divide */ ! 401: clip++; ! 402: if(b.w>0?b.y<b.w:b.y>b.w){ ! 403: if(clip) /* both points behind y=1 plane */ ! 404: { ! 405: /*printf("clipped out of existence\n");*/ ! 406: return; ! 407: } ! 408: t=a; ! 409: a=b; ! 410: b=t; ! 411: clip++; ! 412: } ! 413: /* check for overflow */ ! 414: m = max(max(abs(a.x), abs(a.y)), max(abs(a.z), abs(b.x))); ! 415: m = max(m, max(max(abs(b.y), abs(b.z)), max(abs(a.w), abs(b.w)))); ! 416: if(m > OV) ! 417: { ! 418: m = (m+OV-1)/OV; ! 419: a.x /= m; ! 420: a.y /= m; ! 421: a.z /= m; ! 422: a.w /= m; ! 423: b.x /= m; ! 424: b.y /= m; ! 425: b.z /= m; ! 426: b.w /= m; ! 427: } ! 428: if(clip){ ! 429: n=a.w-a.y; ! 430: d=b.y-a.y-b.w+a.w; ! 431: if(d==0) /* never happens? */ ! 432: return; ! 433: a.x+=(b.x-a.x)*n/d; ! 434: a.y+=(b.y-a.y)*n/d; ! 435: a.z+=(b.z-a.z)*n/d; ! 436: a.w+=(b.w-a.w)*n/d; /* don't use w below */ ! 437: /*printf("clipped to a=(%d,%d,%d,%d), b=(%d,%d,%d,%d)\n", ! 438: a.x,a.y,a.z,a.w,b.x,b.y,b.z,b.w);*/ ! 439: } ! 440: if(clip3scale) ! 441: { ! 442: as = a.w*clip3scale; ! 443: bs = b.w*clip3scale; ! 444: } ! 445: else ! 446: { ! 447: as = a.y; ! 448: bs = b.y; ! 449: } ! 450: A=add(Pt((short)muldiv(a.x, wid, as), (short)muldiv(-a.z, wid, as)), cen); ! 451: B=add(Pt((short)muldiv(b.x, wid, bs), (short)muldiv(-b.z, wid, bs)), cen); ! 452: segment(viewport, A, B, F_OR); ! 453: /*printf("---->drew points (%d,%d) - (%d,%d)\n", A.x, A.y, B.x, B.y);*/ ! 454: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.