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