|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.