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

1.1     ! root        1: 
        !             2: /************************************************************************
        !             3: *
        !             4: *   lfdraw.c
        !             5: *
        !             6: *   Created by Microsoft Corp., 1988
        !             7: *
        !             8: *   This file contains the functions that handle drawing of a "line
        !             9: *   fractal".
        !            10: *
        !            11: *   The fractal always starts out showing one application of the
        !            12: *   similarity transform to the unit interval, centered in the window.
        !            13: *   Clicking on the left mouse button causes the fractal to recurse
        !            14: *   deeper;  on the right button, shallower.
        !            15: *
        !            16: *   Ideas for the future:
        !            17: *   ---------------------
        !            18: *
        !            19: *   1) Add a help screen to explain how to use it.
        !            20: *   2) Allow the user to create or edit a similarity transform.
        !            21: *   3) Allow setting of line attributes per segment of transform.
        !            22: *   4) Save transform to disk and read back, so user can remember the
        !            23: *        good ones (and justify the program!).
        !            24: *   5) Display the level of recursion in a corner of the window.
        !            25: *
        !            26: *
        !            27: *
        !            28: *   Background fractal drawing scheme:
        !            29: *
        !            30: *      To enable the user to interact with the system during
        !            31: *      the drawing of a complicated fractal, the fractal is
        !            32: *      drawn into a bitmap by a background thread.  This thread
        !            33: *      is started at the first WM_PAINT message received by the
        !            34: *      application, and never terminates.
        !            35: *
        !            36: *      The thread's execution is controlled by a semaphore,
        !            37: *      lSemAccumulateFractal.  The thread is initially blocked
        !            38: *      by its semaphore.  When something changes in the environ-
        !            39: *      ment such that the fractal is to be redrawn, or drawn for
        !            40: *      the first time, the semaphore is cleared and the thread
        !            41: *      is off and running.  Note that the environment must be
        !            42: *      set up BEFORE the semaphore is cleared, otherwise the
        !            43: *      fractal may be partially drawn with old parameters.
        !            44: *      The thread automatically resets the semaphore, so that
        !            45: *      as soon as it's done drawing, it has to wait for the signal
        !            46: *      to start again.
        !            47: *
        !            48: *      The fractal is drawn in batches of 500 points per polyline.
        !            49: *      After each polyline is drawn, the background thread invalidates
        !            50: *      the main client rectangle to force a WM_PAINT message to be sent.
        !            51: *      All the paint procedure does is copy the bitmap, whatever
        !            52: *      it's current state, to the screen.  The user therefore
        !            53: *      sees bursts of 500 points at a time as his fractal is drawn.
        !            54: *
        !            55: *      The semaphore is controlled, in greater detail, as follows:
        !            56: *
        !            57: *          Disable background drawing (set semaphore):
        !            58: *
        !            59: *              LineFracInit
        !            60: *                  Don't let second thread start working until a
        !            61: *                  transform has been defined.
        !            62: *
        !            63: *              AccumulateLineFractal
        !            64: *                  Don't start the next one until the user asks for it.
        !            65: *
        !            66: *          Enable background drawing (clear semaphore):
        !            67: *
        !            68: *              WM_BUTTON1UP
        !            69: *              WM_BUTTON2UP
        !            70: *              WM_SIZE & fAutoScale
        !            71: *                  The level of recursion or dimensions of bitmap have
        !            72: *                  changed, so redraw the fractal.
        !            73: *
        !            74: *              Change of transform
        !            75: *                  The similarity transform has changed, so draw the
        !            76: *                  new fractal with the current environment.
        !            77: *
        !            78: *
        !            79: *       Event                                      AccumulateLineFractal
        !            80: *       -----                                      ---------------------
        !            81: *
        !            82: *    WM_BUTTON1UP                                    --------<--------
        !            83: *    WM_BUTTON2UP                                   /                 \
        !            84: *    WM_SIZE & fAutoScale                          |                   |
        !            85: *    Change of transform                           |                   |
        !            86: *         |                                        |                   |
        !            87: *         |                                        V                   |
        !            88: *         +---------clear--------------> +----------------------+      |
        !            89: *                                        | lSemAccumulateFracal |      |
        !            90: *         +----------set---------------> +----------------------+      |
        !            91: *         |                                        |                   |
        !            92: *         |                              if semaphore is clear         ^
        !            93: *    initialization                                |                   |
        !            94: * done with current fractal                        V                   |
        !            95: *                                        +----------------------+      |
        !            96: *                                        |    Draw fractal      |      |
        !            97: *                         WM_PAINT <---- |    into bitmap       |      |
        !            98: *                                        +----------------------+      |
        !            99: *                                                  |                   |
        !           100: *                                                  |                   |
        !           101: *                                                   \                 /
        !           102: *                                                    -------->--------
        !           103: *
        !           104: ************************************************************************/
        !           105: 
        !           106: #define INCL_WIN
        !           107: #define INCL_GPI
        !           108: #define INCL_DOSSEMAPHORES
        !           109: 
        !           110: #include <os2.h>
        !           111: #include <math.h>
        !           112: #include "linefrac.h"
        !           113: 
        !           114: 
        !           115: 
        !           116: 
        !           117: /************************************************************************
        !           118: *
        !           119: *   Function prototypes.
        !           120: *
        !           121: *   These add some error checking to function calls, and prevent
        !           122: *   forward references to functions of undefined return type.
        !           123: *
        !           124: ************************************************************************/
        !           125: 
        !           126: VOID     LineFractal(int, double, double, BOOL, PLINEFRAC);
        !           127: VOID     AddFractalPoint(double, double);
        !           128: VOID     LineFracDraw(void);
        !           129: 
        !           130: 
        !           131: 
        !           132: 
        !           133: /************************************************************************
        !           134: *
        !           135: *   Global Data
        !           136: *
        !           137: *
        !           138: *   These variables reduce the number of parameters passed to
        !           139: *   the recursive fractal drawing function, or to the various
        !           140: *   functions called by the window procedure.
        !           141: *
        !           142: *
        !           143: *   hwndLineFrac       Window handle for the client area.
        !           144: *   LineFracRc         The dimensions of the bitmap (drawing surface).
        !           145: *   LineFracPS         The Presentation Space for drawing fractal.
        !           146: *   LineFracXform      Points to currently selected similarity transform.
        !           147: *   usRecursion                Number of levels of recursion in drawing.
        !           148: *   usPolygonSides     Number of sides to the polygonal frame of "unit
        !           149: *                        intervals".  The fractal transformation is
        !           150: *                        applied to each line segment of the frame.
        !           151: *
        !           152: *   ptPolyLine         Array for accumulating points for PolyLine.
        !           153: *   cptPoly            The number of points in ptPolyLine.
        !           154: *   x, y               Current position, i.e. the endpoint of the
        !           155: *                        last line segment drawn/accumulated.
        !           156: *   lSemAccumulateFractal
        !           157: *                      Semaphore controlling the background thread which
        !           158: *                        accumulates points of fractal.  Clear it to
        !           159: *                        start new fractal.
        !           160: *   fInterrupted       Indicates drawing should be aborted.
        !           161: *   fClearBetween      Indicates that the drawing surface should be
        !           162: *                        cleared to the background color before starting.
        !           163: *
        !           164: *   xscale             These transform each point accumulated, so
        !           165: *   yscale             that the drawing fits into the window,
        !           166: *   xoff               with the original unit interval at the center.
        !           167: *   yoff
        !           168: *
        !           169: *   lColorBack         Background color for the drawing.
        !           170: *   lColor             Line foreground color.
        !           171: *   usStyle            Line style.
        !           172: *   usMixMode          Line foreground mix mode.
        !           173: *
        !           174: ************************************************************************/
        !           175: 
        !           176: extern HWND        hwndLineFrac;
        !           177: extern RECTL       LineFracRc;
        !           178: extern HPS         LineFracPS;
        !           179: extern PLINEFRAC   LineFracXform;
        !           180: extern USHORT      usRecursion;
        !           181: extern USHORT      usPolygonSides;
        !           182: 
        !           183:        POINTL      ptPolyLine[MAX_POINT_COUNT];
        !           184:        ULONG       cptPoly = 0L;
        !           185: extern USHORT      cptMax;
        !           186:        double      x, y;
        !           187: 
        !           188: extern LONG        lSemAccumulateFractal;
        !           189: extern BOOL        fInterrupted;
        !           190: extern BOOL        fClearBetween;
        !           191: 
        !           192: extern double      xscale;
        !           193: extern double      yscale;
        !           194: extern double      xoff;
        !           195: extern double      yoff;
        !           196: 
        !           197: extern LONG        lColorBack;
        !           198: extern LONG        lColor;
        !           199: extern USHORT      usStyle;
        !           200: extern USHORT      usMixMode;
        !           201: 
        !           202: 
        !           203: 
        !           204: 
        !           205: /************************************************************************
        !           206: *
        !           207: *   AccumulateLineFractal
        !           208: *
        !           209: *   Organize the drawing of the fractal.  Runs in an independent
        !           210: *   thread to accumulate the points of the fractal, then calls
        !           211: *   GpiPolyLine to draw into a bitmap. Each time a line is drawn
        !           212: *   (in batches of some appropriate number of points) the client
        !           213: *   rectangle of the application window is invalidated to cause a
        !           214: *   WM_PAINT message.  When the paint message is processed, the
        !           215: *   bitmap will be copied to the display.
        !           216: *
        !           217: *   This thread never terminates.  It is blocked by the semaphore
        !           218: *   lSemAccumulateFractal when there is no work to be done.
        !           219: *
        !           220: ************************************************************************/
        !           221: 
        !           222: VOID FAR PASCAL
        !           223: AccumulateLineFractal()
        !           224: {
        !           225:     double initlength;
        !           226:     double initangle;
        !           227:     double angledecr;
        !           228:     int i;
        !           229: 
        !           230: 
        !           231:     WinInitialize(NULL);       /* initialize ring 2 stack for thread */
        !           232: 
        !           233:     while (1)
        !           234:     {
        !           235:        DosSemRequest(&lSemAccumulateFractal, -1L);
        !           236: 
        !           237: 
        !           238:        /* Initialize the fractal to the unit interval, with nothing
        !           239:         * in the point accumulation buffer.
        !           240:         */
        !           241: 
        !           242:        fInterrupted = FALSE;
        !           243: 
        !           244:        x = 0.0;
        !           245:        y = 0.0;
        !           246: 
        !           247:        if (usPolygonSides == 1)
        !           248:        {
        !           249:            initlength = 1.0;
        !           250:            initangle  = 0.0;
        !           251:            angledecr  = 0.0;
        !           252:        }
        !           253:        else
        !           254:        {
        !           255:            initlength = sin(PI / usPolygonSides);
        !           256:            initangle  = (PI * (usPolygonSides - 2)) / (2 * usPolygonSides);
        !           257:            angledecr  = 2 * PI / usPolygonSides;
        !           258:        }
        !           259: 
        !           260: 
        !           261:        /* Clear the client rectangle to background color. */
        !           262:        if (fClearBetween)
        !           263:            WinFillRect(LineFracPS, &LineFracRc, lColorBack);
        !           264: 
        !           265: 
        !           266:        for (i = 0; i < usPolygonSides; ++i)
        !           267:        {
        !           268: 
        !           269:            /* Anchor the fractal at the left endpoint of the unit interval,
        !           270:             * then draw it to the specified depth of recursion.  If the point
        !           271:             * buffer is not empty afterwards, draw the last PolyLine.
        !           272:             */
        !           273: 
        !           274:            cptPoly = 0L;
        !           275:            AddFractalPoint(x, y);
        !           276:            LineFractal(usRecursion, initlength, initangle, FALSE, LineFracXform);
        !           277: 
        !           278:            if (fInterrupted)
        !           279:                break;
        !           280: 
        !           281:            if (cptPoly > 1)
        !           282:                LineFracDraw();
        !           283: 
        !           284:            initangle -= angledecr;
        !           285:        }
        !           286:     }
        !           287: }
        !           288: 
        !           289: 
        !           290: 
        !           291: 
        !           292: /************************************************************************
        !           293: *
        !           294: *   LineFractal
        !           295: *
        !           296: *   Draw fractal with the given similarity transform.
        !           297: *
        !           298: *   The general idea is to define a transformation to apply to the
        !           299: *   unit line segment, to get a new polyline.  This same transformation
        !           300: *   is then applied to each line segment of the new polyline.  The number
        !           301: *   of successive applications of the similarity transform is set by the
        !           302: *   user.  It's known as the level of recursion of the fractal.
        !           303: *
        !           304: *   Since this is where the point accumulation process will usually
        !           305: *   be, it recognizes the flag fInterrupted  to allow the current
        !           306: *   work to be abandoned.
        !           307: *
        !           308: ************************************************************************/
        !           309: 
        !           310: VOID
        !           311: LineFractal(depth, len, ang, flip, xform)
        !           312: int depth;
        !           313: double len;
        !           314: double ang;
        !           315: BOOL flip;
        !           316: PLINEFRAC xform;
        !           317: {
        !           318:     double newlen;
        !           319:     PLINEFRAC newseg;
        !           320: 
        !           321: 
        !           322:     if (fInterrupted)
        !           323:        return;
        !           324: 
        !           325:     if (depth)
        !           326:     {
        !           327:        /*
        !           328:         *  We have not reached the maximum depth of recursion yet,
        !           329:         *  so apply the similarity transform to the current line
        !           330:         *  segment.
        !           331:         */
        !           332: 
        !           333:        --depth;
        !           334:        newseg = xform;
        !           335:        do
        !           336:        {
        !           337:            newlen  = len * newseg->length;
        !           338:            ang    += newseg->angle * (flip ? -1 : 1);
        !           339:            LineFractal(depth, newlen, ang, flip ^ newseg->flip, xform);
        !           340:        } while ((newseg = newseg->next) != EOLIST);
        !           341:     }
        !           342:     else
        !           343:     {
        !           344:        /*
        !           345:         *  We have reached the maximum depth of recursion, so
        !           346:         *  draw a line segment.
        !           347:         */
        !           348: 
        !           349:        x += len * cos(ang);
        !           350:        y += len * sin(ang);
        !           351:        AddFractalPoint(x, y);
        !           352: 
        !           353:        if (cptPoly >= (ULONG)cptMax)
        !           354:        {
        !           355:            LineFracDraw();
        !           356:            ptPolyLine[0] = ptPolyLine[cptPoly-1];
        !           357:            cptPoly = 1L;
        !           358:        }
        !           359:     }
        !           360: }
        !           361: 
        !           362: 
        !           363: 
        !           364: 
        !           365: /************************************************************************
        !           366: *
        !           367: *   AddFractalPoint
        !           368: *
        !           369: *   Applies the global coordinate transform to the point (x, y), then
        !           370: *   stuffs it into the global PolyLine point array, and increments the
        !           371: *   counts of points in the array.
        !           372: *
        !           373: ************************************************************************/
        !           374: 
        !           375: void
        !           376: AddFractalPoint(x, y)
        !           377: double x,y;
        !           378: {
        !           379:     ptPolyLine[cptPoly].x = (int)(x * xscale + xoff + 0.5);
        !           380:     ptPolyLine[cptPoly].y = (int)(y * yscale + yoff + 0.5);
        !           381:     ++cptPoly;
        !           382: }
        !           383: 
        !           384: 
        !           385: 
        !           386: 
        !           387: /************************************************************************
        !           388: *
        !           389: *   LineFracDraw
        !           390: *
        !           391: *   Set line attributes and draw a batch of lines. Invalidate the client
        !           392: *   rectangle of the main window to cause our latest bitmap to be
        !           393: *   copied there.
        !           394: *
        !           395: ************************************************************************/
        !           396: 
        !           397: VOID
        !           398: LineFracDraw()
        !           399: {
        !           400:     LINEBUNDLE lb;
        !           401: 
        !           402:     lb.lColor = lColor;
        !           403:     lb.usMixMode = usMixMode;
        !           404:     lb.usType = usStyle;
        !           405:     GpiSetAttrs(LineFracPS, PRIM_LINE, LBB_COLOR|LBB_MIX_MODE|LBB_TYPE,
        !           406:                0L, (PBUNDLE)&lb);
        !           407:     GpiSetCurrentPosition( LineFracPS, (PPOINTL)ptPolyLine );
        !           408:     GpiPolyLine( LineFracPS, cptPoly-1, (PPOINTL)&ptPolyLine[1] );
        !           409:     WinInvalidateRect(hwndLineFrac, &LineFracRc, FALSE);
        !           410: }

unix.superglobalmegacorp.com

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