Annotation of pmsdk/samples/linefrac/lfdraw.c, revision 1.1.1.2

1.1       root        1: /************************************************************************
                      2: *
1.1.1.2 ! root        3: *   lfdraw.c -- This file contains "line fractal" drawing routines
1.1       root        4: *
1.1.1.2 ! root        5: *   Created by Microsoft Corporation, 1989
1.1       root        6: *
                      7: *
                      8: *   Background fractal drawing scheme:
                      9: *
                     10: *      To enable the user to interact with the system during
                     11: *      the drawing of a complicated fractal, the fractal is
                     12: *      drawn into a bitmap by a background thread.  This thread
                     13: *      is started at the first WM_PAINT message received by the
                     14: *      application, and never terminates.
                     15: *
                     16: *      The thread's execution is controlled by a semaphore,
1.1.1.2 ! root       17: *      lSemRedraw.  The thread is initially blocked
1.1       root       18: *      by its semaphore.  When something changes in the environ-
                     19: *      ment such that the fractal is to be redrawn, or drawn for
                     20: *      the first time, the semaphore is cleared and the thread
                     21: *      is off and running.  Note that the environment must be
                     22: *      set up BEFORE the semaphore is cleared, otherwise the
                     23: *      fractal may be partially drawn with old parameters.
                     24: *      The thread automatically resets the semaphore, so that
                     25: *      as soon as it's done drawing, it has to wait for the signal
                     26: *      to start again.
                     27: *
1.1.1.2 ! root       28: *      The fractal is drawn in batches of up to 8196 points per polyline.
1.1       root       29: *      After each polyline is drawn, the background thread invalidates
                     30: *      the main client rectangle to force a WM_PAINT message to be sent.
                     31: *      All the paint procedure does is copy the bitmap, whatever
                     32: *      it's current state, to the screen.  The user therefore
1.1.1.2 ! root       33: *      sees bursts of n points at a time as his fractal is drawn.
1.1       root       34: *
                     35: *      The semaphore is controlled, in greater detail, as follows:
                     36: *
                     37: *          Disable background drawing (set semaphore):
                     38: *
1.1.1.2 ! root       39: *              LfInit
1.1       root       40: *                  Don't let second thread start working until a
                     41: *                  transform has been defined.
                     42: *
1.1.1.2 ! root       43: *              LineFractalThread
1.1       root       44: *                  Don't start the next one until the user asks for it.
                     45: *
                     46: *          Enable background drawing (clear semaphore):
                     47: *
                     48: *              WM_BUTTON1UP
                     49: *              WM_BUTTON2UP
1.1.1.2 ! root       50: *              WM_SIZE & fAutoSizePS
1.1       root       51: *                  The level of recursion or dimensions of bitmap have
                     52: *                  changed, so redraw the fractal.
                     53: *
1.1.1.2 ! root       54: *              Change of fractal
        !            55: *              Change of drawing primitive
        !            56: *              Change of attributes
        !            57: *                  If the corresponding redraw flag is enabled for one
        !            58: *                  of these events, then the semaphore is cleared.
        !            59: *
        !            60: *
        !            61: *       Event                                    LineFractalThread
        !            62: *       -----                                    -----------------
        !            63: *
        !            64: *    WM_BUTTON1UP                                --------<--------
        !            65: *    WM_BUTTON2UP                               /                 \
        !            66: *    WM_SIZE & fAutoSizePS                     |                   |
        !            67: *    Change of fractal/primitive/attributes    |                   |
        !            68: *         |                                    |                   |
        !            69: *         |                                    V                   |
        !            70: *         +---------clear----------> +----------------------+      |
        !            71: *                                    |     lSemRedraw       |      |
        !            72: *         +----------set-----------> +----------------------+      |
        !            73: *         |                                    |                   |
        !            74: *         |                          if semaphore is clear         ^
        !            75: *    initialization                            |                   |
        !            76: * done with current fractal                    V                   |
        !            77: *                                    +----------------------+      |
        !            78: *                                    |    Draw fractal      |      |
        !            79: *                     WM_PAINT <---- |    into bitmap       |      |
        !            80: *                                    +----------------------+      |
        !            81: *                                              |                   |
        !            82: *                                              |                   |
        !            83: *                                               \                 /
        !            84: *                                                -------->--------
1.1       root       85: *
                     86: ************************************************************************/
                     87: 
                     88: #define INCL_WIN
                     89: #define INCL_GPI
                     90: #define INCL_DOSSEMAPHORES
1.1.1.2 ! root       91: #define INCL_DOSPROCESS
1.1       root       92: 
                     93: #include <os2.h>
1.1.1.2 ! root       94: #include <mt\math.h>
        !            95: 
        !            96: #define INCL_GLOBALS
        !            97: #define INCL_THREADS
1.1       root       98: #include "linefrac.h"
                     99: 
1.1.1.2 ! root      100: #define INCL_LFTHREAD
        !           101: #define INCL_LFDRAW
        !           102: #include "lffuncs.h"
        !           103: 
1.1       root      104: 
                    105: 
                    106: 
                    107: /************************************************************************
                    108: *
1.1.1.2 ! root      109: *   Global Variables
1.1       root      110: *
                    111: ************************************************************************/
                    112: 
1.1.1.2 ! root      113: extern GLOBALDATA global;
        !           114: extern XFORMDATA  aXform[];
1.1       root      115: 
                    116: 
                    117: 
                    118: 
                    119: /************************************************************************
                    120: *
1.1.1.2 ! root      121: *   LineFractalThread
1.1       root      122: *
1.1.1.2 ! root      123: *   Organize the drawing of the fractal.  Runs in an independent
        !           124: *   thread to accumulate the points of the fractal, then calls
        !           125: *   LfDraw to draw with the selected primitive onto the surface in
        !           126: *   batches of a size selected by the user.  If this thread is the
        !           127: *   top, then all or part of the client rectangle is invalidated
        !           128: *   after drawing to force a WM_PAINT message. When the paint message
        !           129: *   is processed, the image will be copied to the display.
1.1       root      130: *
1.1.1.2 ! root      131: *   This function is entered via _beginthread, which takes care of
        !           132: *   putting the parameter on the stack.
1.1       root      133: *
1.1.1.2 ! root      134: ************************************************************************/
        !           135: 
        !           136: VOID FAR cdecl
        !           137: LineFractalThread(pthr)
        !           138: PTHR pthr;
        !           139: {
        !           140:     HAB hab;
        !           141:     int cFracSegs;
        !           142:     ULONG cptReq;
        !           143:     BOOL fCached;
        !           144:     BOOL fCacheable;
        !           145:     BOOL fModelXformsValid;
        !           146:     PLINEFRAC pXform;         /* linked list of fractal segments */
        !           147: 
        !           148: 
        !           149:     hab = WinInitialize(NULL);       /* initialize ring 2 stack for thread */
        !           150: 
        !           151:     fModelXformsValid = FALSE;
        !           152:     fCached          = FALSE;
        !           153:     fCacheable       = FALSE;
        !           154: 
        !           155:     pthr->pptl       = NULL;
        !           156:     pthr->pmatlf      = NULL;
        !           157: 
        !           158:     while (!pthr->fTimeToDie)
        !           159:     {
        !           160:        /****************************************************************
        !           161:        *
        !           162:        *  Clear the busy flag to indicate we're at the semaphore.
        !           163:        *  If we happen to be the top thread, then force the pointer
        !           164:        *  to be what we expect to see (if we didn't do this, it
        !           165:        *  might stay as an hour glass until the user moves the mouse).
        !           166:        *
        !           167:        ****************************************************************/
        !           168: 
        !           169:        pthr->fBusy = FALSE;
        !           170:        if (LfIsThreadTop(pthr))
        !           171:            if ((global.hptr)[global.usCurPtr])
        !           172:                WinSetPointer(HWND_DESKTOP,(global.hptr)[global.usCurPtr]);
        !           173: 
        !           174: 
        !           175:        /****************************************************************
        !           176:        *
        !           177:        *  Wait for permission to redraw.
        !           178:        *  See if we're supposed to exit.  If not, clear the suicide
        !           179:        *  flag, and set the busy flag.  If we're the top thread, then
        !           180:        *  set the pointer to an hour glass to let the user know we're
        !           181:        *  working on something.
        !           182:        *
        !           183:        ****************************************************************/
        !           184: 
        !           185:        DosSemRequest(&pthr->lSemRedraw, -1L);
        !           186: 
        !           187:        if (pthr->fTimeToDie)
        !           188:            goto lfthread_exit;
        !           189:        pthr->fInterrupted = FALSE;
        !           190:        pthr->fBusy        = TRUE;
        !           191:        if (LfIsThreadTop(pthr))
        !           192:            if (global.hptrWait)
        !           193:                WinSetPointer(HWND_DESKTOP,global.hptrWait);
        !           194: 
        !           195:        /****************************************************************
        !           196:        *
        !           197:        *  Check for changes of attributes.  If anything has changed,
        !           198:        *  this subroutine copies the new stuff over within a critical
        !           199:        *  section.
        !           200:        *
        !           201:        ****************************************************************/
        !           202: 
        !           203:        LfUpdateAttrs(pthr);
        !           204: 
        !           205: 
        !           206:        /****************************************************************
        !           207:        *
        !           208:        *  Check the buffers for points and model transforms.  If we
        !           209:        *  don't have them, or the appropriate attributes have changed
        !           210:        *  such that the ones we have are invalid, allocate for them.
        !           211:        *
        !           212:        ****************************************************************/
        !           213: 
        !           214:        if ((pthr->pptl == NULL) || (pthr->flMiscAttrs & LFA_CPTMAX))
        !           215:        {
        !           216:            if (pthr->pptl != NULL)
        !           217:                DosFreeSeg(*(((PUSHORT)&pthr->pptl)+1));
        !           218:            if (DosAllocSeg(pthr->cptMax * sizeof(POINTL),
        !           219:                           ((PUSHORT)&pthr->pptl)+1, 0))
        !           220:                goto lfthread_exit;
        !           221:        }
        !           222: 
        !           223:        if ((pthr->pmatlf == NULL) || (pthr->flMiscAttrs & LFA_POLYGONSIDES))
        !           224:        {
        !           225:            if (pthr->pmatlf != NULL)
        !           226:                DosFreeSeg(*(((PUSHORT)&pthr->pmatlf)+1));
        !           227:            if (DosAllocSeg(pthr->usPolygonSides * sizeof(MATRIXLF),
        !           228:                           ((PUSHORT)&pthr->pmatlf)+1, 0))
        !           229:                goto lfthread_exit;
        !           230:            fModelXformsValid = FALSE;
        !           231:        }
        !           232: 
        !           233: 
        !           234:        /****************************************************************
        !           235:        *
        !           236:        *  See if we can cache the whole lot of points.  This depends
        !           237:        *  on the fractal, the size of the point cache, and the level
        !           238:        *  of recursion.  Note that we must execute this code the first
        !           239:        *  time through, or fCacheable will be undefined.  We're sure
        !           240:        *  to come here, though, because threads are initialized with
        !           241:        *  all attributes "changed".
        !           242:        *
        !           243:        ****************************************************************/
        !           244: 
        !           245:        if (pthr->flMiscAttrs & (LFA_CPTMAX | LFA_RECURSION | LFA_CURXFORM))
        !           246:        {
        !           247:            if (pthr->flMiscAttrs & LFA_CURXFORM)
        !           248:            {
        !           249:                PLINEFRAC p;
        !           250: 
        !           251:                cFracSegs = 0;
        !           252:                pXform = aXform[pthr->usCurXform - IDM_SHARKTOOTH].pXform;
        !           253:                p = pXform;
        !           254:                while (p != EOLIST)
        !           255:                {
        !           256:                    ++cFracSegs;
        !           257:                    p = p->next;
        !           258:                }
        !           259:            }
        !           260: 
        !           261:            cptReq = (ULONG) exp((double)pthr->usRecursion *
        !           262:                                 log((double)cFracSegs));
        !           263: 
        !           264:            if ((ULONG)pthr->cptMax > cptReq)
        !           265:                fCacheable = TRUE;
        !           266:            else
        !           267:                fCacheable = FALSE;
        !           268: 
        !           269:            fCached = FALSE;
        !           270:        }
        !           271: 
        !           272: 
        !           273:        /****************************************************************
        !           274:        *
        !           275:        *  If the model transforms are invalid, then recompute them.
        !           276:        *  Check first to see if any attributes have changed that
        !           277:        *  would invalidate the transforms.
        !           278:        *
        !           279:        ****************************************************************/
        !           280: 
        !           281:        if (fModelXformsValid)
        !           282:            if (pthr->flMiscAttrs & (LFA_ROTATION | LFA_POLYGONSIDES |
        !           283:                   LFA_XSCALE | LFA_YSCALE | LFA_XOFF | LFA_YOFF))
        !           284:                fModelXformsValid = FALSE;
        !           285: 
        !           286:        if (!fModelXformsValid)
        !           287:        {
        !           288:            LfComputeModelXforms(pthr);
        !           289:            fModelXformsValid = TRUE;
        !           290:        }
        !           291: 
        !           292: 
        !           293:        /****************************************************************
        !           294:        *
        !           295:        *  Clear the change-of-attributes flags that have been examined
        !           296:        *  by the time we get here.
        !           297:        *
        !           298:        ****************************************************************/
        !           299: 
        !           300:        pthr->flMiscAttrs &=
        !           301:          ~(
        !           302:             LFA_CPTMAX    | LFA_RECURSION | LFA_POLYGONSIDES | LFA_CURXFORM  |
        !           303:             LFA_XSCALE    | LFA_YSCALE    | LFA_XOFF         | LFA_YOFF      |
        !           304:             LFA_ROTATION
        !           305:           );
        !           306: 
        !           307: 
        !           308:        /****************************************************************
        !           309:        *
        !           310:        *  Clear the surface if fClearOnRedraw is enabled.
        !           311:        *  If the points are cached, then redraw straight from the cache.
        !           312:        *  Otherwise, anchor the fractal at the left endpoint of the
        !           313:        *  unit interval, then draw it to the specified depth of recursion.
        !           314:        *  If we are able to cache all the points, then nothing will have
        !           315:        *  been drawn when LineFractal returns, so draw the fractal without
        !           316:        *  flushing the cache.  If we were not able to cache all the
        !           317:        *  points, and the buffer is not empty, flush the last batch.
        !           318:        *
        !           319:        ****************************************************************/
        !           320: 
        !           321:        if (pthr->fClearOnRedraw)
        !           322:            LfClearRect(pthr, NULL);
        !           323: 
        !           324:        if (fCached)
        !           325:            LfDraw(pthr, FALSE);
        !           326:        else
        !           327:        {
        !           328:            pthr->x    =  0.0;
        !           329:            pthr->y    =  0.0;
        !           330: 
        !           331:            pthr->cptl = 0L;
        !           332:            LfAddPoint(pthr);
        !           333: 
        !           334:            LineFractal(pthr, pthr->usRecursion, (double)pthr->cxWCS,
        !           335:                        0.0, FALSE, pXform);
        !           336: 
        !           337:            if (!pthr->fInterrupted)
        !           338:            {
        !           339:                if (fCacheable)
        !           340:                {
        !           341:                    LfDraw(pthr, FALSE);
        !           342:                    fCached = TRUE;
        !           343:                }
        !           344:                else
        !           345:                {
        !           346:                    fCached = FALSE;
        !           347:                    if (pthr->cptl > 1L)
        !           348:                        LfDraw(pthr, TRUE);
        !           349:                }
        !           350:            }
        !           351:        }
        !           352:     }
        !           353: 
        !           354: 
        !           355:     /****************************************************************
        !           356:     *
        !           357:     *  Common exit point for thread.  Free up memory allocated
        !           358:     *  by this thread.
        !           359:     *
        !           360:     ****************************************************************/
        !           361: 
        !           362: lfthread_exit:
        !           363: 
        !           364:     if (pthr->pmatlf != NULL)
        !           365:        DosFreeSeg(*(((PUSHORT)&pthr->pmatlf)+1));
        !           366:     if (pthr->pptl != NULL)
        !           367:        DosFreeSeg(*(((PUSHORT)&pthr->pptl)+1));
        !           368: }
        !           369: 
        !           370: 
        !           371: 
        !           372: 
        !           373: /************************************************************************
1.1       root      374: *
1.1.1.2 ! root      375: *   LfUpdateAttrs
1.1       root      376: *
1.1.1.2 ! root      377: *   Update any changed attributes from the global attributes.
1.1       root      378: *
                    379: ************************************************************************/
                    380: 
1.1.1.2 ! root      381: VOID
        !           382: LfUpdateAttrs(pthr)
        !           383: PTHR pthr;
        !           384: {
        !           385: 
        !           386:     DosEnterCritSec();
        !           387:     if (pthr->fUpdateAttrs)
        !           388:     {
        !           389:        if (global.flLineAttrs   & LFA_LINEALL)
        !           390:        {
        !           391:            pthr->lb             = global.lb;
        !           392:            pthr->flLineAttrs   |= global.flLineAttrs;
        !           393:            global.flLineAttrs   = 0L;
        !           394:        }
        !           395:        if (global.flMarkerAttrs & LFA_MARKALL)
        !           396:        {
        !           397:            pthr->mb             = global.mb;
        !           398:            pthr->flMarkerAttrs |= global.flMarkerAttrs;
        !           399:            global.flMarkerAttrs = 0L;
        !           400:        }
        !           401:        if (global.flAreaAttrs   & LFA_AREAALL)
        !           402:        {
        !           403:            pthr->ab             = global.ab;
        !           404:            pthr->flAreaAttrs   |= global.flAreaAttrs;
        !           405:            global.flAreaAttrs   = 0L;
        !           406:        }
        !           407:        if (global.flImageAttrs  & LFA_IMAGEALL)
        !           408:        {
        !           409:            pthr->ib             = global.ib;
        !           410:            pthr->flImageAttrs  |= global.flImageAttrs;
        !           411:            global.flImageAttrs  = 0L;
        !           412:        }
        !           413:        if (global.flMiscAttrs   & LFA_MISCALL)
        !           414:        {
        !           415:            if (global.flMiscAttrs & LFA_CURPRIM)
        !           416:                pthr->usCurPrim      = global.usCurPrim;
        !           417:            if (global.flMiscAttrs & LFA_CURXFORM)
        !           418:                pthr->usCurXform     = global.usCurXform;
        !           419:            if (global.flMiscAttrs & LFA_RECURSION)
        !           420:                pthr->usRecursion    = global.usRecursion;
        !           421:            if (global.flMiscAttrs & LFA_POLYGONSIDES)
        !           422:                pthr->usPolygonSides = global.usPolygonSides;
        !           423:            if (global.flMiscAttrs & LFA_CPTMAX)
        !           424:                pthr->cptMax         = global.cptMax;
        !           425:            if (global.flMiscAttrs & LFA_XOFF)
        !           426:                pthr->dblXOff        = global.dblXOff;
        !           427:            if (global.flMiscAttrs & LFA_YOFF)
        !           428:                pthr->dblYOff        = global.dblYOff;
        !           429:            if (global.flMiscAttrs & LFA_XSCALE)
        !           430:                pthr->dblXScale      = global.dblXScale;
        !           431:            if (global.flMiscAttrs & LFA_YSCALE)
        !           432:                pthr->dblYScale      = global.dblYScale;
        !           433:            if (global.flMiscAttrs & LFA_ROTATION)
        !           434:                pthr->dblRotation    = global.dblRotation;
        !           435:            if (global.flMiscAttrs & LFA_CXWCS)
        !           436:                pthr->cxWCS          = global.cxWCS;
        !           437:            if (global.flMiscAttrs & LFA_CYWCS)
        !           438:                pthr->cyWCS          = global.cyWCS;
        !           439:            pthr->flMiscAttrs  |= global.flMiscAttrs;
        !           440:            global.flMiscAttrs  = 0L;
        !           441:        }
1.1       root      442: 
1.1.1.2 ! root      443:        pthr->fUpdateAttrs  = FALSE;
        !           444:        global.fUpdateAttrs = FALSE;
1.1       root      445: 
1.1.1.2 ! root      446:     }
        !           447:     DosExitCritSec();
1.1       root      448: 
                    449: 
1.1.1.2 ! root      450:     /* Take care of the attribute bundles now. The miscellaneous attributes
        !           451:      * require more processing, so don't clear their flags yet.
        !           452:      */
        !           453: 
        !           454:     if (pthr->flLineAttrs & LFA_LINEALL)
        !           455:     {
        !           456:        GpiSetAttrs(pthr->hps, PRIM_LINE, pthr->flLineAttrs, 0L, &pthr->lb);
        !           457:        pthr->flLineAttrs = 0L;
        !           458:     }
        !           459:     if (pthr->flMarkerAttrs & LFA_MARKALL)
        !           460:     {
        !           461:        GpiSetAttrs(pthr->hps, PRIM_MARKER, pthr->flMarkerAttrs, 0L, &pthr->mb);
        !           462:        pthr->flMarkerAttrs = 0L;
        !           463:     }
        !           464:     if (pthr->flAreaAttrs & LFA_AREAALL)
        !           465:     {
        !           466:        GpiSetAttrs(pthr->hps, PRIM_AREA, pthr->flAreaAttrs, 0L, &pthr->ab);
        !           467:        pthr->flAreaAttrs = 0L;
        !           468:     }
        !           469:     if (pthr->flImageAttrs)
        !           470:     {
        !           471:        GpiSetAttrs(pthr->hps, PRIM_IMAGE, pthr->flImageAttrs, 0L, &pthr->ib);
        !           472:        pthr->flImageAttrs = 0L;
        !           473:     }
        !           474: }
1.1       root      475: 
                    476: 
                    477: 
                    478: 
                    479: /************************************************************************
                    480: *
1.1.1.2 ! root      481: *   LfComputeModelXforms
1.1       root      482: *
1.1.1.2 ! root      483: *   Compute the model transform matrices necessary to draw the fractal
        !           484: *   on each side of the polygonal frame.  The rotation, scaling, and
        !           485: *   translation are all rolled into one matrix for simplicity.
1.1       root      486: *
                    487: ************************************************************************/
                    488: 
1.1.1.2 ! root      489: VOID
        !           490: LfComputeModelXforms(pthr)
        !           491: PTHR pthr;
1.1       root      492: {
1.1.1.2 ! root      493:     double dblXScale, dblYScale;
        !           494:     double dblXOff, dblYOff;
        !           495:     double dblTheta;
        !           496:     double dblRotation, dblSinRotation, dblCosRotation;
        !           497:     double dblSideLen, dblAngleDecr;
        !           498:     double dblXExtDims, dblYExtDims;
        !           499:     double dblHalfXDims, dblHalfYDims;
        !           500:     double dx, dy;
        !           501:     PMATRIXLF pmatlf;
1.1       root      502:     int i;
                    503: 
                    504: 
1.1.1.2 ! root      505:     dblAngleDecr = TWO_PI / (double)pthr->usPolygonSides;
1.1       root      506: 
1.1.1.2 ! root      507:     if (pthr->usPolygonSides == 1)
1.1       root      508:     {
1.1.1.2 ! root      509:        dblSideLen   = 1.0;
        !           510:        dblRotation  = (double) pthr->dblRotation;
        !           511:     }
        !           512:     else
        !           513:     {
        !           514:        /* C 5.1 incorrectly compiles sin(temp_dbl2) in large
        !           515:         * model, where temp_dbl2 is expanded to eliminate all
        !           516:         * temporary variables, therefore I DO use the temp vars.
1.1       root      517:         */
                    518: 
1.1.1.2 ! root      519:        double temp_dbl1, temp_dbl2;
1.1       root      520: 
1.1.1.2 ! root      521:        temp_dbl1    = (double)pthr->usPolygonSides;
        !           522:        temp_dbl2    = PI / temp_dbl1;
        !           523:        dblSideLen   = sin(temp_dbl2);
        !           524:        dblRotation  = PI - dblAngleDecr;
        !           525:        dblRotation  = 0.5 * dblRotation + pthr->dblRotation;
        !           526:     }
1.1       root      527: 
1.1.1.2 ! root      528:     {
        !           529:        double temp_dbl1, temp_dbl2;
1.1       root      530: 
1.1.1.2 ! root      531:        temp_dbl1  = (double) pthr->rcl.xRight;
        !           532:        temp_dbl2  = (double) pthr->cxWCS;
        !           533:        dblXScale  = temp_dbl1 / temp_dbl2;
        !           534:        dblXScale *= pthr->dblXScale * dblSideLen;
        !           535: 
        !           536:        temp_dbl1  = (double) pthr->rcl.yTop;
        !           537:        temp_dbl2  = (double) pthr->cyWCS;
        !           538:        dblYScale  = temp_dbl1 / temp_dbl2;
        !           539:        dblYScale *= pthr->dblYScale * dblSideLen;
        !           540:     }
1.1       root      541: 
1.1.1.2 ! root      542:     dblXExtDims  = (double) pthr->rcl.xRight * pthr->dblXScale;
        !           543:     dblYExtDims  = (double) pthr->rcl.yTop   * pthr->dblYScale;
        !           544:     dblHalfXDims = 0.5 * dblXExtDims;
        !           545:     dblHalfYDims = 0.5 * dblYExtDims;
        !           546:     dblXOff     = (double) pthr->rcl.xRight * pthr->dblXOff + dblHalfXDims;
        !           547:     dblYOff     = (double) pthr->rcl.yTop   * pthr->dblYOff + dblHalfYDims;
1.1       root      548: 
1.1.1.2 ! root      549:     dblTheta    = PI + pthr->dblRotation;
1.1       root      550: 
1.1.1.2 ! root      551:     for (i = 0; i < pthr->usPolygonSides; ++i)
        !           552:     {
        !           553:        dblCosRotation = cos(dblRotation);
        !           554:        dblSinRotation = sin(dblRotation);
1.1       root      555: 
1.1.1.2 ! root      556:        dx = dblHalfXDims * cos(dblTheta);
        !           557:        dy = dblHalfYDims * sin(dblTheta);
1.1       root      558: 
1.1.1.2 ! root      559:        /* 0.000015 = about 1/65536 */
1.1       root      560: 
1.1.1.2 ! root      561:        pmatlf = pthr->pmatlf + i;
        !           562:        pmatlf->fxM11 = (FIXED)(( dblCosRotation * dblXScale + 0.000015) * (double) 0x10000L);
        !           563:        pmatlf->fxM12 = (FIXED)(( dblSinRotation * dblYScale + 0.000015) * (double) 0x10000L);
        !           564:        pmatlf-> lM13 = 0L;
        !           565:        pmatlf->fxM21 = (FIXED)((-dblSinRotation * dblXScale + 0.000015) * (double) 0x10000L);
        !           566:        pmatlf->fxM22 = (FIXED)(( dblCosRotation * dblYScale + 0.000015) * (double) 0x10000L);
        !           567:        pmatlf-> lM23 = 0L;
        !           568:        pmatlf-> lM31 = (LONG) (dblXOff + dx + 0.5);
        !           569:        pmatlf-> lM32 = (LONG) (dblYOff + dy + 0.5);
        !           570:        pmatlf-> lM33 = 1L;
1.1       root      571: 
1.1.1.2 ! root      572:        dblRotation -= dblAngleDecr;
        !           573:        dblTheta    -= dblAngleDecr;
1.1       root      574:     }
                    575: }
                    576: 
                    577: 
                    578: 
                    579: 
                    580: /************************************************************************
                    581: *
                    582: *   LineFractal
                    583: *
                    584: *   Draw fractal with the given similarity transform.
                    585: *
                    586: *   The general idea is to define a transformation to apply to the
                    587: *   unit line segment, to get a new polyline.  This same transformation
                    588: *   is then applied to each line segment of the new polyline.  The number
                    589: *   of successive applications of the similarity transform is set by the
                    590: *   user.  It's known as the level of recursion of the fractal.
                    591: *
                    592: *   Since this is where the point accumulation process will usually
                    593: *   be, it recognizes the flag fInterrupted  to allow the current
                    594: *   work to be abandoned.
                    595: *
                    596: ************************************************************************/
                    597: 
                    598: VOID
1.1.1.2 ! root      599: LineFractal(pthr, depth, len, ang, flip, xform)
        !           600: PTHR pthr;
1.1       root      601: int depth;
                    602: double len;
                    603: double ang;
                    604: BOOL flip;
                    605: PLINEFRAC xform;
                    606: {
                    607:     double newlen;
                    608:     PLINEFRAC newseg;
                    609: 
                    610: 
1.1.1.2 ! root      611:     if (pthr->fInterrupted)
1.1       root      612:        return;
                    613: 
                    614:     if (depth)
                    615:     {
                    616:        /*
                    617:         *  We have not reached the maximum depth of recursion yet,
                    618:         *  so apply the similarity transform to the current line
                    619:         *  segment.
                    620:         */
                    621: 
                    622:        --depth;
                    623:        newseg = xform;
                    624:        do
                    625:        {
                    626:            newlen  = len * newseg->length;
                    627:            ang    += newseg->angle * (flip ? -1 : 1);
1.1.1.2 ! root      628:            LineFractal(pthr, depth, newlen, ang, (flip ^ newseg->flip), xform);
1.1       root      629:        } while ((newseg = newseg->next) != EOLIST);
                    630:     }
                    631:     else
                    632:     {
                    633:        /*
                    634:         *  We have reached the maximum depth of recursion, so
                    635:         *  draw a line segment.
                    636:         */
                    637: 
1.1.1.2 ! root      638:        pthr->x += len * cos(ang);
        !           639:        pthr->y += len * sin(ang);
        !           640:        LfAddPoint(pthr);
        !           641:     }
        !           642: }
        !           643: 
        !           644: 
        !           645: 
        !           646: 
        !           647: /************************************************************************
        !           648: *
        !           649: *   LfAddPoint
        !           650: *
        !           651: *   Applies the global coordinate transform to the point (x, y), then
        !           652: *   stuffs it into the global PolyLine point array, and increments the
        !           653: *   count of points in the array.
        !           654: *
        !           655: ************************************************************************/
        !           656: 
        !           657: VOID
        !           658: LfAddPoint(pthr)
        !           659: PTHR pthr;
        !           660: {
        !           661:     if (pthr->cptl == (ULONG)pthr->cptMax)
        !           662:        LfDraw(pthr, TRUE);
        !           663: 
        !           664:     if (pthr->cptl < (ULONG)pthr->cptMax)
        !           665:     {
        !           666:        (pthr->pptl + pthr->cptl)->x =
        !           667:            (int)(pthr->x + 0.5);
        !           668:        (pthr->pptl + pthr->cptl)->y =
        !           669:            (int)(pthr->y + 0.5);
        !           670:        ++pthr->cptl;
        !           671:     }
        !           672: }
        !           673: 
        !           674: 
        !           675: 
        !           676: 
        !           677: /************************************************************************
        !           678: *
        !           679: *   LfDraw
        !           680: *
        !           681: *   For each segment of the frame, set the model transform and draw the
        !           682: *   cache of points in the current primitive.
        !           683: *
        !           684: *   Invalidate the client rectangle of the main window in case this is
        !           685: *   the top thread, to cause our latest bitmap to be copied there.
        !           686: *
        !           687: ************************************************************************/
        !           688: 
        !           689: VOID
        !           690: LfDraw(pthr, fFlush)
        !           691: PTHR pthr;
        !           692: BOOL fFlush;
        !           693: {
        !           694:     int i;
        !           695:     BOOL myFlush;
        !           696: 
        !           697: 
        !           698:     /* If this is a direct DC, but is not the top thread, then
        !           699:      * don't draw anything.
        !           700:      */
        !           701:     if (pthr->dcType == IDM_DCDIRECT)
        !           702:        if (!LfIsThreadTop(pthr))
        !           703:        {
        !           704:            if (fFlush)
        !           705:                pthr->cptl = 0L;
        !           706:            return;
        !           707:        }
        !           708: 
        !           709: 
        !           710:     if (pthr->fCollectBounds)
        !           711:        GpiResetBoundaryData(pthr->hps);
        !           712: 
        !           713: 
        !           714:     myFlush = FALSE;
        !           715: 
        !           716:     for (i = 0; i < pthr->usPolygonSides; ++i)
        !           717:     {
        !           718:        if (pthr->fInterrupted)
        !           719:            return;
        !           720: 
        !           721:        /* set model transform */
        !           722:        GpiSetModelTransformMatrix(pthr->hps, 9L, pthr->pmatlf+i, TRANSFORM_REPLACE);
        !           723: 
        !           724:        /* we only really flush the last time we use the cache */
        !           725:        if (i == pthr->usPolygonSides - 1)
        !           726:            myFlush = fFlush;
1.1       root      727: 
1.1.1.2 ! root      728:        switch ( pthr->usCurPrim )
1.1       root      729:        {
1.1.1.2 ! root      730:        case IDM_POLYLINE:
        !           731:            LfDrawPolyLine(pthr, myFlush);
        !           732:            break;
        !           733: 
        !           734:        case IDM_POLYFILLET:
        !           735:            LfDrawPolyFillet(pthr, myFlush);
        !           736:            break;
        !           737: 
        !           738:        case IDM_POLYSPLINE:
        !           739:            LfDrawPolySpline(pthr, myFlush);
        !           740:            break;
        !           741: 
        !           742:        case IDM_PEANO:
        !           743:            LfDrawPolyPeano(pthr, myFlush);
        !           744:            break;
        !           745: 
        !           746:        case IDM_POLYMARKER:
        !           747:            LfDrawPolyMarker(pthr, myFlush);
        !           748:            break;
1.1       root      749:        }
1.1.1.2 ! root      750: 
        !           751:        if (pthr->dcType != IDM_DCDIRECT)
        !           752:            if (LfIsThreadTop(pthr))
        !           753:            {
        !           754:                if (pthr->fCollectBounds)
        !           755:                {
        !           756:                    GpiQueryBoundaryData(pthr->hps, &pthr->rclBounds);
        !           757:                    ++(pthr->rclBounds).xRight;
        !           758:                    ++(pthr->rclBounds).yTop;
        !           759:                    WinInvalidateRect(global.hwnd, &pthr->rclBounds, FALSE);
        !           760:                }
        !           761:                else
        !           762:                    WinInvalidateRect(global.hwnd, &pthr->rcl, FALSE);
        !           763:            }
1.1       root      764:     }
                    765: }
                    766: 
                    767: 
                    768: 
                    769: 
                    770: /************************************************************************
                    771: *
1.1.1.2 ! root      772: *   LfDrawPolyLine
1.1       root      773: *
1.1.1.2 ! root      774: *   Draw a polyline using the thread's point buffer.
        !           775: *
        !           776: ************************************************************************/
        !           777: 
        !           778: VOID
        !           779: LfDrawPolyLine(pthr, fFlush)
        !           780: PTHR pthr;
        !           781: BOOL fFlush;
        !           782: {
        !           783:     /* After drawing the line, save the last point to set the
        !           784:        current position before the next call. */
        !           785: 
        !           786:     GpiSetCurrentPosition( pthr->hps, pthr->pptl );
        !           787:     GpiPolyLine( pthr->hps, pthr->cptl-1L, pthr->pptl+1 );
        !           788:     if (fFlush)
        !           789:     {
        !           790:        *pthr->pptl = *(pthr->pptl + pthr->cptl-1);
        !           791:        pthr->cptl = 1L;
        !           792:     }
        !           793: }
        !           794: 
        !           795: 
        !           796: 
        !           797: 
        !           798: /************************************************************************
        !           799: *
        !           800: *   LfDrawPolyFillet
        !           801: *
        !           802: *   Draw a polyfillet using the thread's point buffer.
        !           803: *
        !           804: ************************************************************************/
        !           805: 
        !           806: VOID
        !           807: LfDrawPolyFillet(pthr, fFlush)
        !           808: PTHR pthr;
        !           809: BOOL fFlush;
        !           810: {
        !           811:     /* After drawing the curve, save the last point to set the
        !           812:        current position before the next call. */
        !           813: 
        !           814:     if (pthr->cptl > 2)
        !           815:     {
        !           816:        GpiSetCurrentPosition( pthr->hps, pthr->pptl );
        !           817:        GpiPolyFillet( pthr->hps, pthr->cptl-1L, pthr->pptl+1 );
        !           818:        if (fFlush)
        !           819:        {
        !           820:            *pthr->pptl = *(pthr->pptl + pthr->cptl-1);
        !           821:            pthr->cptl = 1L;
        !           822:        }
        !           823:     }
        !           824: }
        !           825: 
        !           826: 
        !           827: 
        !           828: 
        !           829: /************************************************************************
        !           830: *
        !           831: *   LfDrawPolySpline
        !           832: *
        !           833: *   Draw a polyspline using the thread's point buffer.
1.1       root      834: *
                    835: ************************************************************************/
                    836: 
1.1.1.2 ! root      837: VOID
        !           838: LfDrawPolySpline(pthr, fFlush)
        !           839: PTHR pthr;
        !           840: BOOL fFlush;
1.1       root      841: {
1.1.1.2 ! root      842:     int i;             /* loop counter */
        !           843:     USHORT cptSlack;   /* # points in pptl not usable by PolySpline */
        !           844: 
        !           845:     /* GpiPolySpline expects the number of points to be a
        !           846:        multiple of 3.  If we have a non-multiple of three,
        !           847:        (excluding the first point, which we've used to set
        !           848:        the current position), only pass the largest multiple
        !           849:        of three, saving the rest for the next go-round. */
        !           850: 
        !           851:     cptSlack = (int)((pthr->cptl-1L) % 3) + 1;
        !           852:     GpiSetCurrentPosition( pthr->hps, pthr->pptl );
        !           853:     GpiPolySpline( pthr->hps, pthr->cptl-cptSlack,
        !           854:                   pthr->pptl+1 );
        !           855:     if (fFlush)
        !           856:     {
        !           857:        for (i = 0; i < cptSlack; ++i)
        !           858:            *(pthr->pptl + i) = *(pthr->pptl + pthr->cptl-cptSlack+i);
        !           859:        pthr->cptl = cptSlack;
        !           860:     }
1.1       root      861: }
                    862: 
                    863: 
                    864: 
                    865: 
                    866: /************************************************************************
                    867: *
1.1.1.2 ! root      868: *   LfDrawPolyPeano
1.1       root      869: *
1.1.1.2 ! root      870: *   Draw a chain of Peano primitives using the thread's point buffer.
1.1       root      871: *
                    872: ************************************************************************/
                    873: 
                    874: VOID
1.1.1.2 ! root      875: LfDrawPolyPeano(pthr, fFlush)
        !           876: PTHR pthr;
        !           877: BOOL fFlush;
1.1       root      878: {
1.1.1.2 ! root      879:     LONG a, b, c, d;   /* temporary vars for Peano curvelet calculations */
        !           880:     int cptPeano;      /* current point in pptl in use by Peano curve */
        !           881:     POINTL ptPeano[2]; /* Peano curvelet array to pass to PolyLine */
        !           882: 
        !           883:     for (cptPeano = 0; cptPeano < (int)(pthr->cptl-1L); ++cptPeano)
        !           884:     {
        !           885:        ptPeano[0] = *(pthr->pptl + cptPeano);
        !           886:        ptPeano[1] = *(pthr->pptl + cptPeano+1);
        !           887:        a = (pthr->pptl + cptPeano+1)->x - (pthr->pptl + cptPeano)->x;
        !           888:        b = (pthr->pptl + cptPeano+1)->y - (pthr->pptl + cptPeano)->y;
        !           889:        c = (a + b)/2;
        !           890:        d = (a - b)/2;
        !           891:        if (labs(a) > labs(b))
        !           892:        {
        !           893:            ptPeano[0].x +=  d;
        !           894:            ptPeano[0].y +=  c;
        !           895:        }
        !           896:        else
        !           897:        {
        !           898:            ptPeano[0].x +=  c;
        !           899:            ptPeano[0].y += -d;
        !           900:        }
1.1       root      901: 
1.1.1.2 ! root      902:        GpiSetCurrentPosition( pthr->hps, pthr->pptl + cptPeano);
        !           903:        GpiPolyLine( pthr->hps, 2L, (PPOINTL)ptPeano);
        !           904:     }
        !           905:     if (fFlush)
        !           906:     {
        !           907:        *pthr->pptl = *(pthr->pptl + pthr->cptl-1);
        !           908:        pthr->cptl = 1L;
        !           909:     }
        !           910: }
        !           911: 
        !           912: 
        !           913: 
        !           914: 
        !           915: /************************************************************************
        !           916: *
        !           917: *   LfDrawPolyMarker
        !           918: *
        !           919: *   Draw a list of markers using the thread's point buffer.
        !           920: *
        !           921: ************************************************************************/
        !           922: 
        !           923: VOID
        !           924: LfDrawPolyMarker(pthr, fFlush)
        !           925: PTHR pthr;
        !           926: BOOL fFlush;
        !           927: {
        !           928:     /* I want to draw markers at every point in the array, but
        !           929:        GpiPolyMarker won't draw at the last point!  So, GpiMarker
        !           930:        does the job instead. */
        !           931: 
        !           932:     GpiSetCurrentPosition( pthr->hps, pthr->pptl + pthr->cptl-1);
        !           933:     GpiPolyMarker( pthr->hps, pthr->cptl, pthr->pptl );
        !           934:     GpiMarker   ( pthr->hps,             pthr->pptl + pthr->cptl-1 );
        !           935: 
        !           936:     if (fFlush)
        !           937:        pthr->cptl = 0L;
        !           938: }
        !           939: 
        !           940: 
        !           941: 
        !           942: 
        !           943: /************************************************************************
        !           944: *
        !           945: *   LfClearRect
        !           946: *
        !           947: *   Set the area attributes if needed and fill the bitmap with them.
        !           948: *
        !           949: ************************************************************************/
        !           950: 
        !           951: VOID
        !           952: LfClearRect(pthr, prcl)
        !           953: PTHR pthr;
        !           954: PRECTL prcl;
        !           955: {
        !           956:     PRECTL prclT;
        !           957: 
        !           958:     if (pthr->hps)
        !           959:     {
        !           960:        if (prcl)
        !           961:            prclT = prcl;
        !           962:        else
        !           963:            prclT = &pthr->rcl;
        !           964: 
        !           965:        if (pthr->dcType == IDM_DCDIRECT)
        !           966:        {
        !           967:            /* If direct DC, only blt if top thread. */
        !           968:            if (LfIsThreadTop(pthr))
        !           969:                GpiBitBlt(pthr->hps, NULL, 2L, (PPOINTL)prclT, ROP_PATCOPY, NULL);
        !           970:        }
        !           971:        else
        !           972:        {
        !           973:            GpiBitBlt(pthr->hps, NULL, 2L, (PPOINTL)prclT, ROP_PATCOPY, NULL);
        !           974:            if (LfIsThreadTop(pthr))
        !           975:                WinInvalidateRect(global.hwnd, prclT, FALSE);
        !           976:        }
        !           977:     }
1.1       root      978: }

unix.superglobalmegacorp.com

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