Annotation of pmsdk/samples/shapes/sdraw.c, revision 1.1.1.1

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:     }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.