Annotation of pmsdk/samples/linefrac/lfdraw.c, revision 1.1.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.