home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / MISC / OS2 / PMMANDEL.ZIP / PMMANDEL.C next >
Encoding:
C/C++ Source or Header  |  1990-08-23  |  34.8 KB  |  925 lines

  1. /*----------------------------------------------------------------
  2.    PMMANDEL.C -- OS/2 Presentation Manager Mandelbrot Set Program
  3.                  (c) Charles Petzold, 1990
  4.  
  5.                  Compile using Microsoft C 6.0 for OS/2 1.2
  6.   ----------------------------------------------------------------*/
  7.  
  8. #define INCL_DOS
  9. #define INCL_WIN
  10. #define INCL_GPI
  11. #include <os2.h>
  12. #include <process.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <math.h>
  16. #include "pmmandel.h"
  17.  
  18. #define STACKSIZE             (4096 * sizeof (int))
  19. #define DEF_MAX_ITERATIONS    500
  20. #define WM_IMAGE_COMPLETED    (WM_USER + 1)
  21.  
  22. typedef struct
  23.      {
  24.      double dxMin, dxMax, dyMin, dyMax ;
  25.      }
  26.      COORDDLGSTRUC ;
  27.  
  28. typedef COORDDLGSTRUC *PCOORDDLGSTRUC ;
  29.  
  30. typedef struct
  31.      {
  32.      BOOL  fEnable16, fEnable256 ;
  33.      SHORT sNumColors ;
  34.      }
  35.      COLORDLGSTRUC ;
  36.  
  37. typedef COLORDLGSTRUC *PCOLORDLGSTRUC ;
  38.  
  39. typedef struct
  40.      {
  41.      COORDDLGSTRUC cords ;
  42.      COLORDLGSTRUC clrds ;
  43.      BOOL          fRestart, fTerminate ;
  44.      HPS           hpsClient, hpsMemory ;
  45.      HWND          hwndClient ;
  46.      SHORT         cxMaxClient, cyMaxClient, cxClient, cyClient, cyChar ;
  47.      ULONG         semTriggerDraw, semDoingDraw ;
  48.      USHORT        nMaxIterations ;
  49.      }
  50.      THREADPARAMS ;
  51.  
  52. typedef THREADPARAMS *PTHREADPARAMS ;
  53.  
  54. MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM) ;
  55. MRESULT EXPENTRY CoordDlgProc  (HWND, USHORT, MPARAM, MPARAM) ;
  56. MRESULT EXPENTRY ColorDlgProc  (HWND, USHORT, MPARAM, MPARAM) ;
  57. MRESULT EXPENTRY IterDlgProc   (HWND, USHORT, MPARAM, MPARAM) ;
  58. MRESULT EXPENTRY AboutDlgProc  (HWND, USHORT, MPARAM, MPARAM) ;
  59. VOID             InvertBlock   (HPS, POINTL, POINTL) ;
  60. VOID             CreateIcon    (HPS) ;
  61. VOID             CalcThread    (PTHREADPARAMS) ;
  62. USHORT           Mandelbrot    (struct complex, USHORT) ;
  63.  
  64. CHAR szMessageTitle [] = "PM Mandelbrot Set" ;
  65. HAB  hab ;
  66.  
  67. int main (void)
  68.      {
  69.      static char  szClientClass [] = "PMMandel" ;
  70.      static ULONG flFrameFlags = FCF_TITLEBAR      | FCF_SYSMENU  |
  71.                                  FCF_SIZEBORDER    | FCF_MINMAX   |
  72.                                  FCF_SHELLPOSITION | FCF_TASKLIST |
  73.                                  FCF_ICON          | FCF_MENU ;
  74.      HMQ          hmq ;
  75.      HWND         hwndClient, hwndFrame ;
  76.      QMSG         qmsg ;
  77.  
  78.      hab = WinInitialize (0) ;
  79.      hmq = WinCreateMsgQueue (hab, 0) ;
  80.  
  81.      WinRegisterClass (hab, szClientClass, ClientWndProc, CS_SIZEREDRAW, 0) ;
  82.  
  83.      hwndFrame = WinCreateStdWindow (HWND_DESKTOP, WS_VISIBLE,
  84.                                      &flFrameFlags, szClientClass, NULL,
  85.                                      0L, 0, ID_RESOURCE, &hwndClient) ;
  86.  
  87.      if (hwndFrame != NULL)
  88.           {
  89.           while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
  90.                WinDispatchMsg (hab, &qmsg) ;
  91.  
  92.           WinDestroyWindow (hwndFrame) ;
  93.           }
  94.  
  95.      WinDestroyMsgQueue (hmq) ;
  96.      WinTerminate (hab) ;
  97.      return 0 ;
  98.      }
  99.  
  100. MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  101.      {
  102.      static BOOL         fBlocking ;
  103.      static CHAR         szBuffer [80] ;
  104.      static CHAR         szCoordFormat[] = " Real: %#11.8f, %#11.8f "
  105.                                            " Img: %#11.8f, %#11.8f  " ;
  106.      static HBITMAP      hbm ;
  107.      static HDC          hdcClient, hdcMemory ;
  108.      static int          iThreadStack [STACKSIZE / sizeof (int)] ;
  109.      static POINTL       ptlBeg, ptlEnd ;
  110.      static SHORT        cyDesc, xMousePosBegin ;
  111.      static THREADPARAMS tp = { -2.25, 1.75, -1.5, 1.5 } ;
  112.      static TID          tid ;
  113.      BITMAPINFOHEADER    bmp ;
  114.      double              dTemp ;
  115.      LONG                lNumColors, alBitmapFormats[2] ;
  116.      POINTL              ptl, aptl[TXTBOX_COUNT] ;
  117.      SIZEL               sizl ;
  118.  
  119.      switch (msg)
  120.           {
  121.           case WM_CREATE:
  122.                               // Create presention space for window
  123.  
  124.                hdcClient = WinOpenWindowDC (hwnd) ;
  125.                sizl.cx = 0 ;
  126.                sizl.cy = 0 ;
  127.                tp.hpsClient = GpiCreatePS (hab, hdcClient, &sizl,
  128.                                            PU_PELS    | GPIF_DEFAULT |
  129.                                            GPIT_MICRO | GPIA_ASSOC) ;
  130.  
  131.                               // Get font and text dimensions for status line
  132.  
  133.                GpiQueryTextBox (tp.hpsClient,
  134.                     (LONG) sprintf (szBuffer, szCoordFormat,
  135.                                     0.0, 0.0, 0.0, 0.0),
  136.                     szBuffer, TXTBOX_COUNT, aptl) ;
  137.  
  138.                xMousePosBegin =   (SHORT)  aptl[TXTBOX_CONCAT].x ;
  139.                cyDesc         = - (SHORT)  aptl[TXTBOX_BOTTOMLEFT].y ;
  140.                tp.cyChar      =   (SHORT) (aptl[TXTBOX_TOPLEFT].y + cyDesc) ;
  141.  
  142.                               // Create memory DC and PS for bitmap
  143.  
  144.                hdcMemory = DevOpenDC (hab, OD_MEMORY, "*", 0L, NULL, NULL) ;
  145.                sizl.cx = 0 ;
  146.                sizl.cy = 0 ;
  147.                tp.hpsMemory = GpiCreatePS (hab, hdcMemory, &sizl,
  148.                                            PU_PELS    | GPIF_DEFAULT |
  149.                                            GPIT_MICRO | GPIA_ASSOC) ;
  150.  
  151.                               // Determine size and format of shadow bitmap
  152.  
  153.                tp.cxMaxClient = (SHORT)
  154.                           WinQuerySysValue (HWND_DESKTOP, SV_CXFULLSCREEN) ;
  155.  
  156.                tp.cyMaxClient = (SHORT)
  157.                          (WinQuerySysValue (HWND_DESKTOP, SV_CYFULLSCREEN) -
  158.                           WinQuerySysValue (HWND_DESKTOP, SV_CYMENU)) -
  159.                          tp.cyChar ;
  160.  
  161.                GpiQueryDeviceBitmapFormats (tp.hpsClient, 2L, alBitmapFormats);
  162.  
  163.                               // Create shadow bitmap for storing window image
  164.                               //      and set it in memory presentation space
  165.  
  166.                bmp.cbFix     = sizeof bmp ;
  167.                bmp.cx        = tp.cxMaxClient ;
  168.                bmp.cy        = tp.cyMaxClient ;
  169.                bmp.cPlanes   = (SHORT) alBitmapFormats[0] ;
  170.                bmp.cBitCount = (SHORT) alBitmapFormats[1] ;
  171.  
  172.                hbm = GpiCreateBitmap (tp.hpsMemory, &bmp, 0L, NULL, NULL) ;
  173.  
  174.                if (hbm == NULL)
  175.                     {
  176.                     WinMessageBox (HWND_DESKTOP, hwnd,
  177.                                    "Could not create bitmap for storing image.",
  178.                                    szMessageTitle, 0,
  179.                                    MB_OK | MB_MOVEABLE | MB_ICONEXCLAMATION) ;
  180.  
  181.                     return MRFROMSHORT (1) ;
  182.                     }
  183.  
  184.                GpiSetBitmap (tp.hpsMemory, hbm) ;
  185.                GpiErase (tp.hpsMemory) ;
  186.  
  187.                               // Determine color capability of video display
  188.                               //   and use them to set color dialog structure
  189.  
  190.                DevQueryCaps (hdcClient, CAPS_COLORS, 1L, &lNumColors) ;
  191.  
  192.                if (lNumColors == 2)
  193.                     {
  194.                     tp.clrds.fEnable16  = FALSE ;
  195.                     tp.clrds.fEnable256 = FALSE ;
  196.                     tp.clrds.sNumColors = 2 ;
  197.                     }
  198.                else if (lNumColors >= 16 && lNumColors < 256)
  199.                     {
  200.                     tp.clrds.fEnable16  = TRUE ;
  201.                     tp.clrds.fEnable256 = FALSE ;
  202.                     tp.clrds.sNumColors = 16 ;
  203.                     }
  204.                else
  205.                     {
  206.                     tp.clrds.fEnable16  = TRUE ;
  207.                     tp.clrds.fEnable256 = TRUE ;
  208.                     tp.clrds.sNumColors = 256 ;
  209.                     }
  210.  
  211.                               // Initialize structure fields for thread
  212.  
  213.                tp.fRestart = TRUE ;
  214.                tp.fTerminate = FALSE ;
  215.                tp.nMaxIterations = DEF_MAX_ITERATIONS ;
  216.                tp.hwndClient = hwnd ;
  217.                DosSemSet (&tp.semDoingDraw) ;
  218.                DosSemClear (&tp.semTriggerDraw) ;
  219.  
  220.                               // Start second thread
  221.  
  222.                tid = _beginthread (CalcThread, iThreadStack, STACKSIZE, &tp) ;
  223.  
  224.                if (tid == -1)
  225.                     {
  226.                     WinMessageBox (HWND_DESKTOP, hwnd,
  227.                                    "Could not create second thread.",
  228.                                    szMessageTitle, 0,
  229.                                    MB_OK | MB_MOVEABLE | MB_ICONEXCLAMATION) ;
  230.  
  231.                     return MRFROMSHORT (1) ;
  232.                     }
  233.  
  234.                return 0 ;
  235.  
  236.           case WM_SIZE:
  237.                               // Save new size of client window
  238.  
  239.                DosEnterCritSec () ;
  240.  
  241.                tp.cxClient = SHORT1FROMMP (mp2) ;
  242.                tp.cyClient = SHORT2FROMMP (mp2) ;
  243.  
  244.                DosExitCritSec () ;
  245.                return 0 ;
  246.  
  247.           case WM_COMMAND:
  248.                switch (COMMANDMSG(&msg)->cmd)
  249.                     {
  250.                     case IDM_COORDINATES:
  251.                          DosEnterCritSec () ;
  252.  
  253.                          if (WinDlgBox (HWND_DESKTOP, hwnd, CoordDlgProc,
  254.                                         0, IDD_COORDINATES, &tp.cords))
  255.                               {
  256.                               tp.fRestart = TRUE ;
  257.                               DosSemClear (&tp.semTriggerDraw) ;
  258.                               WinInvalidateRect (hwnd, NULL, FALSE) ;
  259.                               }
  260.  
  261.                          DosExitCritSec () ;
  262.                          return 0 ;
  263.  
  264.                     case IDM_COLORS:
  265.                          DosEnterCritSec () ;
  266.  
  267.                          if (WinDlgBox (HWND_DESKTOP, hwnd, ColorDlgProc,
  268.                                         0, IDD_COLORS, &tp.clrds))
  269.                               {
  270.                               tp.fRestart = TRUE ;
  271.                               DosSemClear (&tp.semTriggerDraw) ;
  272.                               WinInvalidateRect (hwnd, NULL, FALSE) ;
  273.                               }
  274.  
  275.                          DosExitCritSec () ;
  276.                          return 0 ;
  277.  
  278.                     case IDM_ITERATIONS:
  279.                          DosEnterCritSec () ;
  280.  
  281.                          if (WinDlgBox (HWND_DESKTOP, hwnd, IterDlgProc,
  282.                                         0, IDD_ITERATIONS, &tp.nMaxIterations))
  283.                               {
  284.                               tp.fRestart = TRUE ;
  285.                               DosSemClear (&tp.semTriggerDraw) ;
  286.                               WinInvalidateRect (hwnd, NULL, FALSE) ;
  287.                               }
  288.  
  289.                          DosExitCritSec () ;
  290.                          return 0 ;
  291.  
  292.                     case IDM_ABOUT:
  293.                          WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc,
  294.                                     0, IDD_ABOUT, NULL) ;
  295.  
  296.                          return 0 ;
  297.                     }
  298.                break ;
  299.  
  300.           case WM_BUTTON1DBLCLK:
  301.                if (!fBlocking)
  302.                     {
  303.                     DosEnterCritSec () ;
  304.  
  305.                     fBlocking = TRUE ;
  306.                     WinSetCapture (HWND_DESKTOP, hwnd) ;
  307.  
  308.                     ptlBeg.x = ptlEnd.x = MOUSEMSG(&msg)->x ;
  309.                     ptlBeg.y = ptlEnd.y = MOUSEMSG(&msg)->y ;
  310.                     }
  311.                break ;
  312.  
  313.           case WM_MOUSEMOVE:
  314.                               // If blocking, erase prev block and invert block
  315.  
  316.                if (fBlocking)
  317.                     {
  318.                     InvertBlock (tp.hpsClient, ptlBeg, ptlEnd) ;
  319.  
  320.                     ptlEnd.x = MOUSEMSG(&msg)->x ;
  321.                     ptlEnd.y = MOUSEMSG(&msg)->y ;
  322.  
  323.                     InvertBlock (tp.hpsClient, ptlBeg, ptlEnd) ;
  324.                     }
  325.                else
  326.                     DosEnterCritSec () ;
  327.  
  328.                               // Display mouse coordinates in status line
  329.  
  330.                GpiSetBackMix (tp.hpsClient, BM_OVERPAINT) ;
  331.  
  332.                ptl.x = xMousePosBegin ;
  333.                ptl.y = tp.cyClient - tp.cyChar + cyDesc ;
  334.  
  335.                GpiCharStringAt (tp.hpsClient, &ptl,
  336.                     (LONG) sprintf (szBuffer, "Mou: %#11.8f, %#11.8f",
  337.                         tp.cords.dxMin + MOUSEMSG(&msg)->x *
  338.                            (tp.cords.dxMax - tp.cords.dxMin) / tp.cxMaxClient,
  339.                         tp.cords.dyMin + MOUSEMSG(&msg)->y *
  340.                            (tp.cords.dyMax - tp.cords.dyMin) / tp.cyMaxClient),
  341.                     szBuffer) ;
  342.  
  343.                if (!fBlocking)
  344.                     DosExitCritSec () ;
  345.  
  346.                break ;
  347.  
  348.           case WM_BUTTON1DOWN:
  349.                if (fBlocking)
  350.                     {
  351.                     fBlocking = FALSE ;
  352.  
  353.                     WinSetCapture (HWND_DESKTOP, NULL) ;
  354.  
  355.                     ptlEnd.x = MOUSEMSG(&msg)->x ;
  356.                     ptlEnd.y = MOUSEMSG(&msg)->y ;
  357.  
  358.                     InvertBlock (tp.hpsClient, ptlBeg, ptlEnd) ;
  359.  
  360.                               // calculate new coordinates
  361.  
  362.                     dTemp = tp.cords.dxMin + min (ptlBeg.x, ptlEnd.x) *
  363.                          (tp.cords.dxMax - tp.cords.dxMin) / tp.cxMaxClient ;
  364.  
  365.                     tp.cords.dxMax = tp.cords.dxMin +
  366.                          max (ptlBeg.x, ptlEnd.x) *
  367.                          (tp.cords.dxMax - tp.cords.dxMin) / tp.cxMaxClient ;
  368.  
  369.                     tp.cords.dxMin = dTemp ;
  370.  
  371.                     dTemp = tp.cords.dyMin + min (ptlBeg.y, ptlEnd.y) *
  372.                          (tp.cords.dyMax - tp.cords.dyMin) / tp.cyMaxClient ;
  373.  
  374.                     tp.cords.dyMax = tp.cords.dyMin +
  375.                          max (ptlBeg.y, ptlEnd.y) *
  376.                          (tp.cords.dyMax - tp.cords.dyMin) / tp.cyMaxClient ;
  377.  
  378.                     tp.cords.dyMin = dTemp ;
  379.  
  380.                               // restart the calculation
  381.  
  382.                     tp.fRestart = TRUE ;
  383.                     DosSemClear (&tp.semTriggerDraw) ;
  384.                     WinInvalidateRect (hwnd, NULL, FALSE) ;
  385.                     DosExitCritSec () ;
  386.                     }
  387.                break ;
  388.  
  389.           case WM_CHAR:
  390.                                 // stop the blocking
  391.                if (fBlocking)
  392.                     {
  393.                     fBlocking = FALSE ;
  394.  
  395.                     InvertBlock (tp.hpsClient, ptlBeg, ptlEnd) ;
  396.  
  397.                     WinSetCapture (HWND_DESKTOP, NULL) ;
  398.  
  399.                     DosExitCritSec () ;
  400.                     }
  401.                return 0 ;
  402.  
  403.           case WM_IMAGE_COMPLETED:
  404.                WinMessageBox (HWND_DESKTOP, hwnd, "The image is completed.",
  405.                               szMessageTitle, 0,
  406.                               MB_OK | MB_MOVEABLE | MB_ICONASTERISK) ;
  407.                return 0 ;
  408.  
  409.           case WM_PAINT:
  410.                DosEnterCritSec () ;
  411.                WinBeginPaint (hwnd, tp.hpsClient, NULL) ;
  412.                GpiErase (tp.hpsClient) ;
  413.  
  414.                               // Copy bitmap to client window
  415.  
  416.                aptl[0].x = 0 ;
  417.                aptl[0].y = 0 ;
  418.                aptl[1].x = tp.cxClient ;
  419.                aptl[1].y = tp.cyClient - tp.cyChar ;
  420.                aptl[2].x = 0 ;
  421.                aptl[2].y = 0 ;
  422.  
  423.                GpiBitBlt (tp.hpsClient, tp.hpsMemory, 3L, aptl,
  424.                           ROP_SRCCOPY, BBO_IGNORE) ;
  425.  
  426.                               // Display status line
  427.  
  428.                ptl.x = 0 ;
  429.                ptl.y = tp.cyClient - tp.cyChar + cyDesc ;
  430.  
  431.                GpiCharStringAt (tp.hpsClient, &ptl,
  432.                     (LONG) sprintf (szBuffer, szCoordFormat,
  433.                                     tp.cords.dxMin, tp.cords.dxMax,
  434.                                     tp.cords.dyMin, tp.cords.dyMax),
  435.                     szBuffer) ;
  436.  
  437.                WinEndPaint (tp.hpsClient) ;
  438.                DosExitCritSec () ;
  439.                return 0 ;
  440.  
  441.           case WM_DESTROY:
  442.                tp.fTerminate = TRUE ;
  443.                tp.fRestart = TRUE ;
  444.                DosSemClear (&tp.semTriggerDraw) ;
  445.  
  446.                DosSemWait (&tp.semDoingDraw, SEM_INDEFINITE_WAIT) ;
  447.  
  448.                GpiSetBitmap (tp.hpsMemory, NULL) ;
  449.                GpiDestroyPS (tp.hpsClient) ;
  450.                GpiDestroyPS (tp.hpsMemory) ;
  451.                DevCloseDC (hdcMemory) ;
  452.                GpiDeleteBitmap (hbm) ;
  453.                return 0 ;
  454.           }
  455.      return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  456.      }
  457.  
  458. MRESULT EXPENTRY CoordDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  459.      {
  460.      static CHAR           szBuffer [40] ;
  461.      static PCOORDDLGSTRUC pcords ;
  462.  
  463.      switch (msg)
  464.           {
  465.           case WM_INITDLG:
  466.                pcords = (PCOORDDLGSTRUC) PVOIDFROMMP (mp2) ;
  467.  
  468.                sprintf (szBuffer, "%10.7f", pcords->dxMin) ;
  469.                WinSetDlgItemText (hwnd, IDD_XMIN, szBuffer) ;
  470.  
  471.                sprintf (szBuffer, "%10.7f", pcords->dxMax) ;
  472.                WinSetDlgItemText (hwnd, IDD_XMAX, szBuffer) ;
  473.  
  474.                sprintf (szBuffer, "%10.7f", pcords->dyMin) ;
  475.                WinSetDlgItemText (hwnd, IDD_YMIN, szBuffer) ;
  476.  
  477.                sprintf (szBuffer, "%10.7f", pcords->dyMax) ;
  478.                WinSetDlgItemText (hwnd, IDD_YMAX, szBuffer) ;
  479.                return 0 ;
  480.  
  481.           case WM_COMMAND:
  482.                switch (SHORT1FROMMP (mp1))
  483.                     {
  484.                     case DID_OK:
  485.                          WinQueryDlgItemText (hwnd, IDD_XMIN,
  486.                                               sizeof szBuffer, szBuffer) ;
  487.                          pcords->dxMin = atof (szBuffer) ;
  488.  
  489.                          WinQueryDlgItemText (hwnd, IDD_XMAX,
  490.                                               sizeof szBuffer, szBuffer) ;
  491.                          pcords->dxMax = atof (szBuffer) ;
  492.  
  493.                          WinQueryDlgItemText (hwnd, IDD_YMIN,
  494.                                               sizeof szBuffer, szBuffer) ;
  495.                          pcords->dyMin = atof (szBuffer) ;
  496.  
  497.                          WinQueryDlgItemText (hwnd, IDD_YMAX,
  498.                                               sizeof szBuffer, szBuffer) ;
  499.                          pcords->dyMax = atof (szBuffer) ;
  500.  
  501.                          WinDismissDlg (hwnd, TRUE) ;
  502.                          return 0 ;
  503.  
  504.                     case DID_CANCEL:
  505.                          WinDismissDlg (hwnd, FALSE) ;
  506.                          return 0 ;
  507.                     }
  508.                break ;
  509.                }
  510.      return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  511.      }
  512.  
  513. MRESULT EXPENTRY ColorDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  514.      {
  515.      static PCOLORDLGSTRUC pclrds ;
  516.      static SHORT          sNumColors, sID ;
  517.  
  518.      switch (msg)
  519.           {
  520.           case WM_INITDLG:
  521.                pclrds = (PCOLORDLGSTRUC) PVOIDFROMMP (mp2) ;
  522.  
  523.                if (!pclrds->fEnable16)
  524.                     WinEnableWindow (WinWindowFromID (hwnd, IDD_COLOR16),
  525.                                      FALSE) ;
  526.  
  527.                if (!pclrds->fEnable256)
  528.                     WinEnableWindow (WinWindowFromID (hwnd, IDD_COLOR256),
  529.                                      FALSE) ;
  530.  
  531.                sNumColors = pclrds->sNumColors ;
  532.  
  533.                if (sNumColors == 2)
  534.                     sID = IDD_COLOR2 ;
  535.  
  536.                else if (sNumColors == 16)
  537.                     sID = IDD_COLOR16 ;
  538.  
  539.                else if (sNumColors == 256)
  540.                     sID = IDD_COLOR256 ;
  541.  
  542.                WinSendDlgItemMsg (hwnd, sID, BM_SETCHECK,
  543.                                   MPFROM2SHORT (TRUE, 0), NULL) ;
  544.  
  545.                WinSetFocus (HWND_DESKTOP, WinWindowFromID (hwnd, sID)) ;
  546.                return MRFROMSHORT (1) ;
  547.  
  548.           case WM_CONTROL:
  549.                switch (SHORT1FROMMP (mp1))
  550.                     {
  551.                     case IDD_COLOR2:    sNumColors = 2   ;  break ;
  552.                     case IDD_COLOR16:   sNumColors = 16  ;  break ;
  553.                     case IDD_COLOR256:  sNumColors = 256 ;  break ;
  554.                     }
  555.                return 0 ;
  556.  
  557.           case WM_COMMAND:
  558.                switch (SHORT1FROMMP (mp1))
  559.                     {
  560.                     case DID_OK:
  561.                          pclrds->sNumColors = sNumColors ;
  562.                          WinDismissDlg (hwnd, TRUE) ;
  563.                          return 0 ;
  564.  
  565.                     case DID_CANCEL:
  566.                          WinDismissDlg (hwnd, FALSE) ;
  567.                          return 0 ;
  568.                     }
  569.                break ;
  570.                }
  571.      return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  572.      }
  573.  
  574. MRESULT EXPENTRY IterDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  575.      {
  576.      static CHAR    szBuffer [10] ;
  577.      static PUSHORT pnMaxIterations ;
  578.  
  579.      switch (msg)
  580.           {
  581.           case WM_INITDLG:
  582.                pnMaxIterations = (PUSHORT) PVOIDFROMMP (mp2) ;
  583.  
  584.                WinSendDlgItemMsg (hwnd, IDD_ITER, EM_SETTEXTLIMIT,
  585.                                   MPFROMSHORT (sizeof szBuffer - 1), NULL) ;
  586.  
  587.                WinSetDlgItemShort (hwnd, IDD_ITER, *pnMaxIterations, FALSE) ;
  588.                return 0 ;
  589.  
  590.           case WM_COMMAND:
  591.                switch (SHORT1FROMMP (mp1))
  592.                     {
  593.                     case DID_OK:
  594.                          WinQueryDlgItemShort (hwnd, IDD_ITER,
  595.                                                pnMaxIterations, FALSE) ;
  596.  
  597.                          if (*pnMaxIterations == 0)
  598.                               {
  599.                               WinMessageBox (HWND_DESKTOP, hwnd,
  600.                                    "Zero Iterations?  Get real!",
  601.                                    szMessageTitle, 0,
  602.                                    MB_OK | MB_MOVEABLE | MB_ICONEXCLAMATION) ;
  603.  
  604.                               return 0 ;
  605.                               }
  606.  
  607.                          WinDismissDlg (hwnd, TRUE) ;
  608.                          return 0 ;
  609.  
  610.                     case DID_CANCEL:
  611.                          WinDismissDlg (hwnd, FALSE) ;
  612.                          return 0 ;
  613.                     }
  614.                break ;
  615.                }
  616.      return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  617.      }
  618.  
  619. MRESULT EXPENTRY AboutDlgProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  620.      {
  621.      switch (msg)
  622.           {
  623.           case WM_COMMAND:
  624.                switch (SHORT1FROMMP (mp1))
  625.                     {
  626.                     case DID_OK:
  627.                     case DID_CANCEL:
  628.                          WinDismissDlg (hwnd, TRUE) ;
  629.                          return 0 ;
  630.                     }
  631.                break ;
  632.                }
  633.      return WinDefDlgProc (hwnd, msg, mp1, mp2) ;
  634.      }
  635.  
  636. VOID InvertBlock (HPS hps, POINTL ptlBeg, POINTL ptlEnd)
  637.      {
  638.      RECTL rcl ;
  639.  
  640.      if (ptlBeg.x != ptlEnd.x && ptlBeg.y != ptlEnd.y)
  641.           {
  642.           rcl.xLeft   = min (ptlBeg.x, ptlEnd.x) ;
  643.           rcl.xRight  = max (ptlBeg.x, ptlEnd.x) ;
  644.           rcl.yBottom = min (ptlBeg.y, ptlEnd.y) ;
  645.           rcl.yTop    = max (ptlBeg.y, ptlEnd.y) ;
  646.  
  647.           WinInvertRect (hps, &rcl) ;
  648.           }
  649.      }
  650.  
  651. VOID CalcThread (PTHREADPARAMS ptp)
  652.      {
  653.      static LONG    alColor16 [] = { CLR_DARKBLUE, CLR_DARKGREEN, CLR_DARKCYAN,
  654.                                      CLR_DARKRED,  CLR_DARKPINK,  CLR_BROWN,
  655.                                      CLR_DARKGRAY, CLR_PALEGRAY,  CLR_BLUE,
  656.                                      CLR_GREEN,    CLR_CYAN,      CLR_RED,
  657.                                      CLR_PINK,     CLR_YELLOW,    CLR_WHITE } ;
  658.  
  659.      static LONG    alColor256[] = { 0x000055, 0x0000AA, 0x0000FF, 0x002400,
  660.                                      0x002455, 0x0024AA, 0x0024FF, 0x004900,
  661.                                      0x004955, 0x0049AA, 0x0049FF, 0x006D00,
  662.                                      0x006D55, 0x006DAA, 0x006DFF, 0x009200,
  663.                                      0x009255, 0x0092AA, 0x0092FF, 0x00B600,
  664.                                      0x00B655, 0x00B6AA, 0x00B6FF, 0x00DB00,
  665.                                      0x00DB55, 0x00DBAA, 0x00DBFF, 0x00FF00,
  666.                                      0x00FF55, 0x00FFAA, 0x00FFFF, 0x240000,
  667.                                      0x240055, 0x2400AA, 0x2400FF, 0x242400,
  668.                                      0x242455, 0x2424AA, 0x2424FF, 0x244900,
  669.                                      0x244955, 0x2449AA, 0x2449FF, 0x246D00,
  670.                                      0x246D55, 0x246DAA, 0x246DFF, 0x249200,
  671.                                      0x249255, 0x2492AA, 0x2492FF, 0x24B600,
  672.                                      0x24B655, 0x24B6AA, 0x24B6FF, 0x24DB00,
  673.                                      0x24DB55, 0x24DBAA, 0x24DBFF, 0x24FF00,
  674.                                      0x24FF55, 0x24FFAA, 0x24FFFF, 0x490000,
  675.                                      0x490055, 0x4900AA, 0x4900FF, 0x492400,
  676.                                      0x492455, 0x4924AA, 0x4924FF, 0x494900,
  677.                                      0x494955, 0x4949AA, 0x4949FF, 0x496D00,
  678.                                      0x496D55, 0x496DAA, 0x496DFF, 0x499200,
  679.                                      0x499255, 0x4992AA, 0x4992FF, 0x49B600,
  680.                                      0x49B655, 0x49B6AA, 0x49B6FF, 0x49DB00,
  681.                                      0x49DB55, 0x49DBAA, 0x49DBFF, 0x49FF00,
  682.                                      0x49FF55, 0x49FFAA, 0x49FFFF, 0x6D0000,
  683.                                      0x6D0055, 0x6D00AA, 0x6D00FF, 0x6D2400,
  684.                                      0x6D2455, 0x6D24AA, 0x6D24FF, 0x6D4900,
  685.                                      0x6D4955, 0x6D49AA, 0x6D49FF, 0x6D6D00,
  686.                                      0x6D6D55, 0x6D6DAA, 0x6D6DFF, 0x6D9200,
  687.                                      0x6D9255, 0x6D92AA, 0x6D92FF, 0x6DB600,
  688.                                      0x6DB655, 0x6DB6AA, 0x6DB6FF, 0x6DDB00,
  689.                                      0x6DDB55, 0x6DDBAA, 0x6DDBFF, 0x6DFF00,
  690.                                      0x6DFF55, 0x6DFFAA, 0x6DFFFF, 0x920000,
  691.                                      0x920055, 0x9200AA, 0x9200FF, 0x922400,
  692.                                      0x922455, 0x9224AA, 0x9224FF, 0x924900,
  693.                                      0x924955, 0x9249AA, 0x9249FF, 0x926D00,
  694.                                      0x926D55, 0x926DAA, 0x926DFF, 0x929200,
  695.                                      0x929255, 0x9292AA, 0x9292FF, 0x92B600,
  696.                                      0x92B655, 0x92B6AA, 0x92B6FF, 0x92DB00,
  697.                                      0x92DB55, 0x92DBAA, 0x92DBFF, 0x92FF00,
  698.                                      0x92FF55, 0x92FFAA, 0x92FFFF, 0xB60000,
  699.                                      0xB60055, 0xB600AA, 0xB600FF, 0xB62400,
  700.                                      0xB62455, 0xB624AA, 0xB624FF, 0xB64900,
  701.                                      0xB64955, 0xB649AA, 0xB649FF, 0xB66D00,
  702.                                      0xB66D55, 0xB66DAA, 0xB66DFF, 0xB69200,
  703.                                      0xB69255, 0xB692AA, 0xB692FF, 0xB6B600,
  704.                                      0xB6B655, 0xB6B6AA, 0xB6B6FF, 0xB6DB00,
  705.                                      0xB6DB55, 0xB6DBAA, 0xB6DBFF, 0xB6FF00,
  706.                                      0xB6FF55, 0xB6FFAA, 0xB6FFFF, 0xDB0000,
  707.                                      0xDB0055, 0xDB00AA, 0xDB00FF, 0xDB2400,
  708.                                      0xDB2455, 0xDB24AA, 0xDB24FF, 0xDB4900,
  709.                                      0xDB4955, 0xDB49AA, 0xDB49FF, 0xDB6D00,
  710.                                      0xDB6D55, 0xDB6DAA, 0xDB6DFF, 0xDB9200,
  711.                                      0xDB9255, 0xDB92AA, 0xDB92FF, 0xDBB600,
  712.                                      0xDBB655, 0xDBB6AA, 0xDBB6FF, 0xDBDB00,
  713.                                      0xDBDB55, 0xDBDBAA, 0xDBDBFF, 0xDBFF00,
  714.                                      0xDBFF55, 0xDBFFAA, 0xDBFFFF, 0xFF0000,
  715.                                      0xFF0055, 0xFF00AA, 0xFF00FF, 0xFF2400,
  716.                                      0xFF2455, 0xFF24AA, 0xFF24FF, 0xFF4900,
  717.                                      0xFF4955, 0xFF49AA, 0xFF49FF, 0xFF6D00,
  718.                                      0xFF6D55, 0xFF6DAA, 0xFF6DFF, 0xFF9200,
  719.                                      0xFF9255, 0xFF92AA, 0xFF92FF, 0xFFB600,
  720.                                      0xFFB655, 0xFFB6AA, 0xFFB6FF, 0xFFDB00,
  721.                                      0xFFDB55, 0xFFDBAA, 0xFFDBFF, 0xFFFF00,
  722.                                      0xFFFF55, 0xFFFFAA, 0xFFFFFF } ;
  723.      struct complex cmplxPoint ;
  724.      HAB            hab ;
  725.      LONG           lColorUse ;
  726.      POINTL         aptl[3] ;
  727.      SHORT          i, x, y ;
  728.      USHORT         nIteration ;
  729.  
  730.      hab = WinInitialize (0) ;
  731.  
  732.      while (!ptp->fTerminate)
  733.           {
  734.           DosSemWait (&ptp->semTriggerDraw, SEM_INDEFINITE_WAIT) ;
  735.  
  736.           if (ptp->fTerminate)
  737.                break ;
  738.  
  739.           DosSemSet (&ptp->semDoingDraw) ;
  740.  
  741.           DosEnterCritSec () ;
  742.  
  743.           GpiErase (ptp->hpsMemory) ;
  744.  
  745.           if (ptp->clrds.sNumColors == 256)
  746.                {
  747.                GpiCreateLogColorTable (ptp->hpsClient, LCOL_PURECOLOR,
  748.                                        LCOLF_RGB, 0L, 0L, NULL) ;
  749.                GpiCreateLogColorTable (ptp->hpsMemory, LCOL_PURECOLOR,
  750.                                        LCOLF_RGB, 0L, 0L, NULL) ;
  751.                }
  752.           else
  753.                {
  754.                GpiCreateLogColorTable (ptp->hpsClient, LCOL_RESET,
  755.                                        LCOLF_INDRGB, 0L, 0L, NULL) ;
  756.                GpiCreateLogColorTable (ptp->hpsMemory, LCOL_RESET,
  757.                                        LCOLF_INDRGB, 0L, 0L, NULL) ;
  758.                }
  759.  
  760.           ptp->fRestart = FALSE ;
  761.  
  762.           DosExitCritSec () ;
  763.  
  764.                               // Loop for fat-bits down to pixels.
  765.  
  766.           for (i = 64 ; i > 0 ; i /= 2)
  767.                {
  768.                               // Loop for rows
  769.  
  770.                for (y = 0 ; y < ptp->cyMaxClient ; y += i)
  771.                     {
  772.                               // Loop for columns
  773.  
  774.                     for (x = 0 ; x < ptp->cxMaxClient ; x += i)
  775.                          {
  776.                               // If bit already drawn, skip it
  777.  
  778.                          if ((i != 64) && (x & 1 == 0) && (y & 1 == 0))
  779.                               continue ;
  780.  
  781.                               // Calculate the complex point
  782.  
  783.                          DosEnterCritSec () ;
  784.  
  785.                          cmplxPoint.x =  ptp->cords.dxMin + x *
  786.                                         (ptp->cords.dxMax - ptp->cords.dxMin) /
  787.                                          ptp->cxMaxClient ;
  788.  
  789.                          cmplxPoint.y =  ptp->cords.dyMin + y *
  790.                                         (ptp->cords.dyMax - ptp->cords.dyMin) /
  791.                                          ptp->cyMaxClient ;
  792.  
  793.                               // Find the number of iterations
  794.  
  795.                          nIteration = Mandelbrot (cmplxPoint,
  796.                                                   ptp->nMaxIterations) ;
  797.  
  798.                               // Determine the color to use
  799.  
  800.                          if (ptp->clrds.sNumColors == 2)
  801.  
  802.                               lColorUse = (nIteration == ptp->nMaxIterations ?
  803.                                              CLR_BLACK : CLR_WHITE) ;
  804.  
  805.                          else if (ptp->clrds.sNumColors == 16)
  806.  
  807.                               lColorUse = (nIteration == ptp->nMaxIterations ?
  808.                                    CLR_BLACK : alColor16 [nIteration % 15]) ;
  809.  
  810.                          else if (ptp->clrds.sNumColors == 256)
  811.  
  812.                               lColorUse = (nIteration == ptp->nMaxIterations ?
  813.                                    RGB_BLACK : alColor256 [nIteration % 255]) ;
  814.  
  815.                          GpiSetColor (ptp->hpsMemory, lColorUse) ;
  816.  
  817.                               // Draw on the bitmap
  818.  
  819.                          aptl[0].x = x ;
  820.                          aptl[0].y = y ;
  821.  
  822.                          if (i > 1)
  823.                               {
  824.                               aptl[1].x = min (x + i, ptp->cxMaxClient) ;
  825.                               aptl[1].y = min (y + i, ptp->cyMaxClient) ;
  826.  
  827.                               GpiBitBlt (ptp->hpsMemory, NULL,
  828.                                          2L, aptl, ROP_PATCOPY, 0L) ;
  829.                               }
  830.                          else
  831.                               GpiSetPel (ptp->hpsMemory, aptl) ;
  832.  
  833.                          DosExitCritSec () ;
  834.  
  835.                          if (ptp->fRestart)
  836.                               break ;
  837.                          }
  838.  
  839.                     if (ptp->fRestart)
  840.                          break ;
  841.  
  842.                     DosEnterCritSec () ;
  843.  
  844.                               // For each row, draw the bitmap on the window
  845.  
  846.                     if (y < ptp->cyClient - ptp->cyChar)
  847.                          {
  848.                          aptl[0].x = 0 ;
  849.                          aptl[0].y = y ;
  850.  
  851.                          aptl[1].x = ptp->cxClient ;
  852.                          aptl[1].y = min (y + i, ptp->cyClient - ptp->cyChar) ;
  853.  
  854.                          aptl[2].x = 0 ;
  855.                          aptl[2].y = y ;
  856.  
  857.                          GpiBitBlt (ptp->hpsClient, ptp->hpsMemory,
  858.                                     3L, aptl, ROP_SRCCOPY, 0L);
  859.                          }
  860.  
  861.                     DosExitCritSec () ;
  862.                     }
  863.  
  864.                if (ptp->fRestart)
  865.                     break ;
  866.                }
  867.  
  868.           if (!ptp->fRestart)
  869.                {
  870.                DosSemSet (&ptp->semTriggerDraw) ;
  871.                WinPostMsg (ptp->hwndClient, WM_IMAGE_COMPLETED, NULL, NULL) ;
  872.                }
  873.  
  874.           DosSemClear (&ptp->semDoingDraw) ;
  875.           }
  876.  
  877.      WinTerminate (hab) ;
  878.      _endthread () ;
  879.      }
  880.  
  881. USHORT Mandelbrot (struct complex cmplxPoint, USHORT nMaxIterations)
  882.      {
  883.      struct complex cmplxSquare, cmplxTemp, cmplxAccum ;
  884.      USHORT         n ;
  885.  
  886.      cmplxAccum = cmplxPoint ;
  887.  
  888.                     // "Cheat" a little for speed
  889.  
  890.      if (cmplxPoint.x >= -0.750 && cmplxPoint.x <= 0.250 &&
  891.          cmplxPoint.y >= -0.625 && cmplxPoint.y <= 0.625)
  892.           {
  893.           cmplxTemp    = cmplxPoint ;
  894.           cmplxTemp.x += .125 ;
  895.  
  896.           if (cabs (cmplxTemp) < .625)
  897.                return nMaxIterations ;
  898.           }
  899.  
  900.      else if (cmplxPoint.x >= -1.250 && cmplxPoint.x <= -0.750 &&
  901.               cmplxPoint.y >= -0.250 && cmplxPoint.y <=  0.250)
  902.           {
  903.           cmplxTemp    = cmplxPoint ;
  904.           cmplxTemp.x += 1.0 ;
  905.  
  906.           if (cabs (cmplxTemp) < .25)
  907.                return nMaxIterations ;
  908.           }
  909.                     // Done cheating
  910.  
  911.      for (n = 0 ; n < nMaxIterations ; n++)
  912.           {
  913.           cmplxSquare.x = cmplxAccum.x * cmplxAccum.x ;
  914.           cmplxSquare.y = cmplxAccum.y * cmplxAccum.y ;
  915.  
  916.           if (cmplxSquare.x + cmplxSquare.y >= 4.0)
  917.                break ;
  918.  
  919.           cmplxAccum.y = 2 * cmplxAccum.x  * cmplxAccum.y  + cmplxPoint.y ;
  920.           cmplxAccum.x =     cmplxSquare.x - cmplxSquare.y + cmplxPoint.x ;
  921.           }
  922.  
  923.      return n ;
  924.      }
  925.