|
|
1.1 ! root 1: /*--------------------------------------------------------*\ ! 2: SDRAW.C - 3D to 2D transformations and draw routines ! 3: \*--------------------------------------------------------*/ ! 4: ! 5: #include <stddef.h> ! 6: #include <os2.h> ! 7: #include <math.h> ! 8: #include "sstruct.h" ! 9: ! 10: extern SHAPE rgshape []; ! 11: ! 12: POINT3D pt3FillBuffer [MAX_POINTS]; ! 13: ! 14: extern INT yPelAdjust; ! 15: ! 16: ! 17: /* ! 18: * ScalePoint: ! 19: * - replace destination point by source point after scaling ! 20: */ ! 21: ! 22: VOID ScalePoint ( ! 23: POINT3D *ppt3Source, ! 24: POINT3D *ppt3Dest, ! 25: LONG iScale ) ! 26: { ! 27: ppt3Dest->x = (INT) ( ((LONG) ppt3Source->x * iScale) >> 6 ); ! 28: ppt3Dest->y = (INT) ( ((LONG) ppt3Source->y * iScale) >> 6 ); ! 29: ppt3Dest->z = (INT) ( ((LONG) ppt3Source->z * iScale) >> 6 ); ! 30: } ! 31: ! 32: ! 33: /* ! 34: * ChangeScale: ! 35: * - to be called after a window changes size ! 36: * - scales a shape's appropriate variables for the new size ! 37: * - the centre of the window indicates the new window size ! 38: */ ! 39: ! 40: extern VOID ChangeScale ( ! 41: PSV psv ) ! 42: { ! 43: LONG xScale = psv->ptCentre.x; ! 44: LONG yScale = (psv->ptCentre.y << 10) / yPelAdjust; ! 45: LONG iScale = (xScale > yScale) ? yScale : xScale; ! 46: INIT *pinit = rgshape [psv->iShape].pinit; ! 47: ! 48: if (iScale < MIN_SCALE) ! 49: { ! 50: /* set lower bound on the scale of a shape */ ! 51: ! 52: iScale = MIN_SCALE; ! 53: } ! 54: ! 55: /* scale the initial size of the shape */ ! 56: ! 57: ScalePoint (&pinit->pt3SizeMid, &psv->pt3Size, iScale); ! 58: psv->pt3SizeMid = psv->pt3Size; ! 59: ! 60: /* scale the magnitude of the sinusoidal size change */ ! 61: ! 62: ScalePoint (&pinit->pt3SizeMag, &psv->pt3SizeMag, iScale); ! 63: ! 64: /* scale the viewing distance */ ! 65: /* (so that perspective is independent of window size) */ ! 66: ! 67: psv->zViewDist = pinit->zViewDist * iScale; ! 68: } ! 69: ! 70: ! 71: /* ! 72: * lSin: ! 73: * - fast integer sine function with granularity of 1 degree ! 74: * - constraint: -360 <= angle <= 360 ! 75: * - returns the sine of an angle * 16384 (shifted left by 14) ! 76: */ ! 77: ! 78: LONG lSin( ! 79: INT iAngle ) ! 80: { ! 81: static INT iSinTable [91] = ! 82: { 0, 286, 572, 857, 1143, 1428, 1713, 1997, 2280, 2563, 2845, 3126, ! 83: 3406, 3686, 3964, 4240, 4516, 4790, 5063, 5334, 5604, 5872, 6138, ! 84: 6402, 6664, 6924, 7182, 7438, 7692, 7943, 8192, 8438, 8682, 8923, ! 85: 9162, 9397, 9630, 9860, 10087, 10311, 10531, 10749, 10963, 11174, ! 86: 11381, 11585, 11786, 11982, 12176, 12365, 12551, 12733, 12911, 13085, ! 87: 13255, 13421, 13583, 13741, 13894, 14044, 14189, 14330, 14466, 14598, ! 88: 14726, 14849, 14968, 15082, 15191, 15296, 15396, 15491, 15582, 15668, ! 89: 15749, 15826, 15897, 15964, 16026, 16083, 16135, 16182, 16225, 16262, ! 90: 16294, 16322, 16344, 16362, 16374, 16382, 16384 }; ! 91: ! 92: if (iAngle < 0) ! 93: iAngle += 360; ! 94: ! 95: if (iAngle < 180) ! 96: if (iAngle < 90) ! 97: return( (LONG) iSinTable [iAngle] ); ! 98: else ! 99: return( (LONG) iSinTable [180 - iAngle] ); ! 100: else ! 101: if (iAngle < 270) ! 102: return( (LONG) -iSinTable [iAngle - 180] ); ! 103: else ! 104: return( (LONG) -iSinTable [360 - iAngle] ); ! 105: } ! 106: ! 107: ! 108: /* ! 109: * iAngleAdd (macro): ! 110: * - adds the second angle to first angle ! 111: * - stores result (which is in range 0 to 359) in the first angle ! 112: */ ! 113: ! 114: #define iAngleAdd( iA1,iA2) \ ! 115: if ( ((iA1) += (iA2)) < 0 ) (iA1) += 360; \ ! 116: else if ( (iA1) >= 360 ) (iA1) -= 360; ! 117: ! 118: ! 119: /* ! 120: * AddToAngle: ! 121: * - adds the 3D angular velocity to the 3D angle ! 122: */ ! 123: ! 124: VOID AddToAngle( ! 125: POINT3D *ppt3Angle, ! 126: POINT3D *ppt3AngVel ) ! 127: { ! 128: iAngleAdd (ppt3Angle->x, ppt3AngVel->x) ! 129: iAngleAdd (ppt3Angle->y, ppt3AngVel->y) ! 130: iAngleAdd (ppt3Angle->z, ppt3AngVel->z) ! 131: } ! 132: ! 133: ! 134: /* ! 135: * CalcSize: ! 136: * - calculates the new size for sinusoidal size variation ! 137: * ie. <size> = <middle> + <magnitude> * SIN (<angle>) ! 138: */ ! 139: ! 140: VOID CalcSize( ! 141: POINT3D *ppt3Size, ! 142: POINT3D *ppt3SizeMid, ! 143: POINT3D *ppt3SizeMag, ! 144: POINT3D *ppt3SizeAng ) ! 145: { ! 146: ppt3Size->x = ppt3SizeMid->x + ! 147: (INT) (ppt3SizeMag->x * lSin( ppt3SizeAng->x ) >> 14); ! 148: ppt3Size->y = ppt3SizeMid->y + ! 149: (INT) (ppt3SizeMag->y * lSin( ppt3SizeAng->y ) >> 14); ! 150: ppt3Size->z = ppt3SizeMid->z + ! 151: (INT) (ppt3SizeMag->z * lSin( ppt3SizeAng->z ) >> 14); ! 152: } ! 153: ! 154: ! 155: /* ! 156: * CalcPoints: ! 157: * - transform the 3D points to 2D points ! 158: * - transformation includes: ! 159: * a) scaling points ! 160: * b) rotating points around x/y/z axis ! 161: * c) perspective transformation ! 162: * d) translating to centre of window ! 163: */ ! 164: ! 165: VOID CalcPoints ( ! 166: PSV psv, ! 167: INT cPoints, ! 168: POINT3D rgpt3 [], ! 169: POINTL rgpt [] ) ! 170: { ! 171: LONG sinx = lSin( psv->pt3Angle.x ); ! 172: LONG cosx = lSin((psv->pt3Angle.x + 90) % 360 ); ! 173: LONG siny = lSin( psv->pt3Angle.y ); ! 174: LONG cosy = lSin((psv->pt3Angle.y + 90) % 360 ); ! 175: LONG sinz = lSin( psv->pt3Angle.z ); ! 176: LONG cosz = lSin((psv->pt3Angle.z + 90) % 360 ); ! 177: LONG x, y, z, x2, y2, z2; ! 178: LONG z0 = psv->zViewDist; ! 179: INT i; ! 180: LONG xSize = psv->pt3Size.x; ! 181: LONG ySize = psv->pt3Size.y; ! 182: LONG zSize = psv->pt3Size.z; ! 183: ! 184: for( i=0; i < cPoints; i++ ) ! 185: { ! 186: /* scale points relative to x/y/z axis of shape */ ! 187: ! 188: x = (LONG) rgpt3 [i].x * xSize; ! 189: y = (LONG) rgpt3 [i].y * ySize; ! 190: z = (LONG) rgpt3 [i].z * zSize; ! 191: ! 192: /* rotate around X axis */ ! 193: ! 194: y2 = ( y * cosx - z * sinx ) >> 14; ! 195: z2 = ( z * cosx + y * sinx ) >> 14; ! 196: ! 197: /* rotate around Y axis */ ! 198: ! 199: z = ( z2 * cosy - x * siny ) >> 14; ! 200: x2 = ( x * cosy + z2 * siny ) >> 14; ! 201: ! 202: /* rotate around Z axis */ ! 203: ! 204: x = ( x2 * cosz - y2 * sinz ) >> 14; ! 205: y = ( y2 * cosz + x2 * sinz ) >> 14; ! 206: ! 207: if (psv->fShaded) ! 208: { ! 209: /* store points used for shading */ ! 210: /* (before perspective - light source is at infinity) */ ! 211: ! 212: pt3FillBuffer [i].x = (INT) (x >> 8); ! 213: pt3FillBuffer [i].y = (INT) (y >> 8); ! 214: pt3FillBuffer [i].z = (INT) (z >> 8); ! 215: } ! 216: ! 217: if (psv->fPerspective) ! 218: { ! 219: /* avoid overflow when doing perspective */ ! 220: ! 221: x = (x * (z0 >> 6)) / ((z0 - z) >> 6); ! 222: y = (y * (z0 >> 6)) / ((z0 - z) >> 6); ! 223: } ! 224: ! 225: /* store translated points in 2D table */ ! 226: /* note: points must be rescaled to fit in window */ ! 227: ! 228: rgpt [i].x = (x >> 8) + psv->ptCentre.x; ! 229: rgpt [i].y = (( (y >> 8) * yPelAdjust ) >> 10) + psv->ptCentre.y; ! 230: } ! 231: } ! 232: ! 233: ! 234: /* ! 235: * DrawLines: ! 236: * - draws a shape using the lines of the object (clipping off) ! 237: */ ! 238: ! 239: VOID DrawLines ( ! 240: HPS hps, ! 241: LINE rgline [], ! 242: POINTL rgpt [] ) ! 243: { ! 244: INT i; ! 245: INT iPoint1, iPoint2 = -1; ! 246: ! 247: for( i=0; (iPoint1 = rgline [i].p1) >= 0; i++ ) ! 248: { ! 249: if (iPoint1 != iPoint2) ! 250: { ! 251: GpiSetCurrentPosition( hps, &rgpt [iPoint1] ); ! 252: } ! 253: iPoint2 = rgline [i].p2; ! 254: GpiLine( hps, &rgpt [iPoint2] ); ! 255: } ! 256: } ! 257: ! 258: ! 259: /* ! 260: * DrawFaces: ! 261: * - draws a shape using the faces of the object (clipping on) ! 262: */ ! 263: ! 264: VOID DrawFaces ( ! 265: HPS hps, ! 266: FACE rgface [], ! 267: POINTL rgpt [] ) ! 268: { ! 269: INT i = 0; ! 270: INT iEndFace, cSpread; ! 271: INT iPoint1, iPoint2, iPoint3; ! 272: LONG xV1, yV1, xV2, yV2; ! 273: LONG zNormal; ! 274: ! 275: iPoint1 = rgface [i++]; ! 276: do ! 277: { ! 278: /* get 3 points spread out on surface */ ! 279: ! 280: iEndFace = i; ! 281: while (rgface [iEndFace++] >= 0) ! 282: ; ! 283: cSpread = iEndFace - i + 1; ! 284: ! 285: if (cSpread > 5) ! 286: { ! 287: cSpread /= 3; ! 288: iPoint2 = rgface [i - 1 + cSpread]; ! 289: iPoint3 = rgface [i - 1 + 2 * cSpread]; ! 290: } ! 291: else ! 292: { ! 293: iPoint2 = rgface [i]; ! 294: iPoint3 = rgface [i + 1]; ! 295: } ! 296: ! 297: /* calculate z coordinate of normal (using 3 points on surface) */ ! 298: ! 299: xV1 = rgpt [iPoint3].x - rgpt [iPoint2].x; ! 300: yV1 = rgpt [iPoint3].y - rgpt [iPoint2].y; ! 301: xV2 = rgpt [iPoint1].x - rgpt [iPoint2].x; ! 302: yV2 = rgpt [iPoint1].y - rgpt [iPoint2].y; ! 303: zNormal = xV1 * yV2 - yV1 * xV2; ! 304: ! 305: if (zNormal > 0) ! 306: { ! 307: /* face is pointing towards the user */ ! 308: ! 309: /* draw the perimeter of the face */ ! 310: ! 311: GpiSetCurrentPosition( hps, &rgpt [iPoint1] ); ! 312: while (( iPoint2 = rgface [i++] ) >= 0) ! 313: GpiLine( hps, &rgpt [iPoint2] ); ! 314: GpiLine( hps, &rgpt [iPoint1] ); ! 315: ! 316: while (iPoint2 == -1) ! 317: { ! 318: /* draw a pattern associated with the face */ ! 319: ! 320: iPoint1 = rgface [i++]; ! 321: GpiSetCurrentPosition( hps, &rgpt [iPoint1] ); ! 322: while ((iPoint2 = rgface [i++] ) >= 0) ! 323: GpiLine( hps, &rgpt [iPoint2] ); ! 324: } ! 325: } ! 326: else ! 327: /* face is not visible - skip over it */ ! 328: ! 329: while (rgface [i++] >= -1) ! 330: ; ! 331: } ! 332: while (( iPoint1 = rgface [i++] ) >= 0); ! 333: } ! 334: ! 335: ! 336: /* ! 337: * ChangeShapePosition: ! 338: * - calculate 2D points for new position ! 339: * - blank out old position ! 340: * - draw in new position ! 341: */ ! 342: ! 343: extern VOID ChangeShapePosition ( ! 344: PSV psv ) ! 345: { ! 346: HPS hps; ! 347: POINTL *pptTemp; ! 348: SHAPE *pshape = &rgshape [psv->iShape]; ! 349: OBJECT *pobject = pshape->pobject; ! 350: ! 351: if (psv->fVarySize) ! 352: { ! 353: /* vary the size */ ! 354: ! 355: AddToAngle (&psv->pt3SizeAng, &pshape->pinit->pt3SizeVel ); ! 356: CalcSize (&psv->pt3Size, &psv->pt3SizeMid, ! 357: &psv->pt3SizeMag, &psv->pt3SizeAng ); ! 358: } ! 359: ! 360: /* rotate */ ! 361: ! 362: AddToAngle (&psv->pt3Angle, &psv->pt3AngVel ); ! 363: ! 364: /* calculate new position */ ! 365: ! 366: CalcPoints (psv, pobject->cPoints, pobject->rgpt3, psv->rgptNew ); ! 367: ! 368: hps = psv->hpsClient; ! 369: ! 370: /* blank out old position */ ! 371: ! 372: if (psv->fErased) ! 373: psv->fErased = FALSE; ! 374: else ! 375: { ! 376: GpiSetColor (hps, CLR_WHITE); ! 377: if (psv->fClipping) ! 378: DrawFaces (hps, pobject->rgface, psv->rgptOld ); ! 379: else ! 380: DrawLines (hps, pobject->rgline, psv->rgptOld ); ! 381: } ! 382: ! 383: /* draw at new position */ ! 384: ! 385: GpiSetColor (hps, CLR_BLACK); ! 386: if (psv->fClipping) ! 387: DrawFaces (hps, pobject->rgface, psv->rgptNew ); ! 388: else ! 389: DrawLines (hps, pobject->rgline, psv->rgptNew ); ! 390: ! 391: /* swap 2D points buffers - new becomes old */ ! 392: ! 393: pptTemp = psv->rgptOld; ! 394: psv->rgptOld = psv->rgptNew; ! 395: psv->rgptNew = pptTemp; ! 396: } ! 397: ! 398: ! 399: VOID DrawAndFill ( ! 400: PSV psv ) ! 401: { ! 402: HPS hps = psv->hpsClient; ! 403: OBJECT *pobject = rgshape [psv->iShape].pobject; ! 404: FACE *rgface = pobject->rgface; ! 405: POINTL *rgpt = psv->rgptNew; ! 406: INT i = 0; ! 407: INT iEndFace, cSpread; ! 408: INT iPoint1, iPoint2, iPoint3; ! 409: LONG xV1, yV1, zV1, xV2, yV2, zV2; ! 410: LONG iDiv; ! 411: LONG xN, yN, zN; ! 412: LONG zNormal; ! 413: LONG sinx = lSin( psv->pt2LightAng.x ); ! 414: LONG cosx = lSin((psv->pt2LightAng.x + 90) % 360 ); ! 415: LONG siny = lSin( psv->pt2LightAng.y ); ! 416: LONG cosy = lSin((psv->pt2LightAng.y + 90) % 360 ); ! 417: POINTL pt; ! 418: ! 419: CalcPoints (psv, pobject->cPoints, pobject->rgpt3, rgpt ); ! 420: ! 421: GpiSavePS (hps); ! 422: GpiCreateLogColorTable (hps, LCOL_RESET, LCOLF_RGB, 0L, 0L, NULL); ! 423: ! 424: iPoint1 = rgface [i++]; ! 425: do ! 426: { ! 427: /* get 3 points spread out on surface */ ! 428: ! 429: iEndFace = i; ! 430: while (rgface [iEndFace++] >= 0) ! 431: ; ! 432: cSpread = iEndFace - i + 1; ! 433: ! 434: if (cSpread > 5) ! 435: { ! 436: cSpread /= 3; ! 437: iPoint2 = rgface [i - 1 + cSpread]; ! 438: iPoint3 = rgface [i - 1 + 2 * cSpread]; ! 439: } ! 440: else ! 441: { ! 442: iPoint2 = rgface [i]; ! 443: iPoint3 = rgface [i + 1]; ! 444: } ! 445: ! 446: /* calculate z coordinate of normal (using 3 points on surface) */ ! 447: ! 448: xV1 = rgpt [iPoint3].x - rgpt [iPoint2].x; ! 449: yV1 = rgpt [iPoint3].y - rgpt [iPoint2].y; ! 450: xV2 = rgpt [iPoint1].x - rgpt [iPoint2].x; ! 451: yV2 = rgpt [iPoint1].y - rgpt [iPoint2].y; ! 452: zNormal = xV1 * yV2 - yV1 * xV2; ! 453: ! 454: if (zNormal > 0) ! 455: { ! 456: /* face is pointing towards the user */ ! 457: ! 458: /* normalize vectors */ ! 459: ! 460: xV1 = pt3FillBuffer [iPoint3].x - pt3FillBuffer [iPoint2].x; ! 461: yV1 = pt3FillBuffer [iPoint3].y - pt3FillBuffer [iPoint2].y; ! 462: zV1 = pt3FillBuffer [iPoint3].z - pt3FillBuffer [iPoint2].z; ! 463: ! 464: xV2 = pt3FillBuffer [iPoint1].x - pt3FillBuffer [iPoint2].x; ! 465: yV2 = pt3FillBuffer [iPoint1].y - pt3FillBuffer [iPoint2].y; ! 466: zV2 = pt3FillBuffer [iPoint1].z - pt3FillBuffer [iPoint2].z; ! 467: ! 468: iDiv = (LONG) sqrt ((double) (xV1 * xV1 + yV1 * yV1 + zV1 * zV1) ); ! 469: xV1 = (xV1 << 10) / iDiv; ! 470: yV1 = (yV1 << 10) / iDiv; ! 471: zV1 = (zV1 << 10) / iDiv; ! 472: ! 473: iDiv = (LONG) sqrt ((double) (xV2 * xV2 + yV2 * yV2 + zV2 * zV2) ); ! 474: xV2 = (xV2 << 10) / iDiv; ! 475: yV2 = (yV2 << 10) / iDiv; ! 476: zV2 = (zV2 << 10) / iDiv; ! 477: ! 478: /* calculate normal to surface */ ! 479: ! 480: xN = (yV1 * zV2 - zV1 * yV2) >> 10; ! 481: yN = (zV1 * xV2 - xV1 * zV2) >> 10; ! 482: zN = (xV1 * yV2 - yV1 * xV2) >> 10; ! 483: ! 484: /* rotate normal around X and Y axes */ ! 485: ! 486: zN = ( zN * cosx + xN * sinx ) >> 14; ! 487: zN = ( zN * cosy + yN * siny ) >> 14; ! 488: ! 489: /* change range of zNormal from [0,1023] to [128,255] */ ! 490: ! 491: zNormal = zN >> 3; ! 492: if (zNormal < 0) ! 493: zNormal = 0; ! 494: else if (zNormal > 127) ! 495: zNormal = 127; ! 496: zNormal += 128; ! 497: ! 498: GpiSetColor (hps, zNormal); ! 499: ! 500: /* draw the perimeter of the face */ ! 501: ! 502: GpiBeginArea (hps, BA_NOBOUNDARY | BA_ALTERNATE); ! 503: ! 504: GpiSetCurrentPosition( hps, &rgpt [iPoint1] ); ! 505: while (( iPoint2 = rgface [i++] ) >= 0) ! 506: GpiLine( hps, &rgpt [iPoint2] ); ! 507: GpiLine( hps, &rgpt [iPoint1] ); ! 508: ! 509: GpiEndArea (hps); ! 510: ! 511: GpiSetColor (hps, zNormal << 16 ); ! 512: ! 513: while (iPoint2 == -1) ! 514: { ! 515: /* draw a pattern associated with the face */ ! 516: ! 517: iPoint1 = rgface [i++]; ! 518: GpiSetCurrentPosition( hps, &rgpt [iPoint1] ); ! 519: while ((iPoint2 = rgface [i++] ) >= 0) ! 520: GpiLine( hps, &rgpt [iPoint2] ); ! 521: } ! 522: } ! 523: else ! 524: /* face is not visible - skip over it */ ! 525: ! 526: while (rgface [i++] >= -1) ! 527: ; ! 528: } ! 529: while (( iPoint1 = rgface [i++] ) >= 0); ! 530: ! 531: GpiRestorePS (hps, -1L); ! 532: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.