home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Graphics / Graphics.zip / fractz.zip / FRACTZ.CPP < prev    next >
C/C++ Source or Header  |  1994-01-17  |  87KB  |  2,348 lines

  1.  
  2. /*+---------------------------------------------------------------------------+*/
  3. /*                                                                             */
  4. /*                        fractz                                               */
  5. /*                  a fractal generater                                        */
  6. /*               Copyright (c)  Tom Stokes  1993, 1994                                    */
  7. /*+---------------------------------------------------------------------------+*/
  8.  
  9.  
  10. /*+--------------------------------------------------------------------------+*/
  11. /*| System and library header files.                                         |*/
  12. /*+--------------------------------------------------------------------------+*/
  13.  
  14. #define _FP_INLINE              /* generate inline FPU code */
  15. #define INCL_WIN
  16. #define INCL_DEV
  17. #define INCL_GPI
  18. #define INCL_DOS
  19.  
  20. #include <os2.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. //#include <math.h>
  25. //#include <bsememf.h>
  26. #include <complex.h>
  27.  
  28. /*+--------------------------------------------------------------------------+*/
  29. /*| Application header files.                                                |*/
  30. /*+--------------------------------------------------------------------------+*/
  31.  
  32. #include "fractz.h"
  33.  
  34. /*+--------------------------------------------------------------------------+*/
  35. /*| Internal function prototypes.                                            |*/
  36. /*+--------------------------------------------------------------------------+*/
  37.  
  38. static void DrawingThread(void);  // thread
  39. static void Sleeper(void);        // thread
  40. static void Colorer(void);        // thread
  41.  
  42. static void InitTitle( HAB, HWND, char *, char *);
  43. static void UpdateTitle(HWND, char *, char *);
  44.  
  45. static MRESULT EXPENTRY ClientWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 );
  46. static MRESULT EXPENTRY SettingsDlg(HWND, ULONG, MPARAM, MPARAM);
  47. static MRESULT EXPENTRY HelpDlgProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2 );
  48.  
  49. static void DisplayMessage( HAB, ULONG );
  50.  
  51. /*+--------------------------------------------------------------------------+*/
  52. /*| Static global variables and local constants.                             |*/
  53. /*+--------------------------------------------------------------------------+*/
  54.  
  55. #define WINDOW_CLASS   "My_Window"          /* window class name              */
  56. #define MSG_BOX_ID     256                  /* error message box id           */
  57. #define STRING_LENGTH  128                  /* size of buffer used for strings*/
  58. #define STACK_SIZE     8192UL               /* stack size for second thread   */
  59. #define PERIOD_CHECK                        /* check for periodicity          */
  60.  
  61. //////////////////////////////////////////////////////////////////////////////////
  62. //   note on C/set++ &  __BCPLUSPLUS__
  63. // C/set++ defines PCSZ as: typedef const char *PCSZ and then uses it
  64. // as the parameter type in many APIs. BCOS2, on the other hand, does not
  65. // define PCSZ but instead uses: typedef unsigned char *PSZ.
  66. // Thus the following typedef within the __BCPLUSPLUS__ pre-defined macro
  67. // allows living in both worlds.
  68. //////////////////////////////////////////////////////////////////////////////////
  69.  
  70. #ifdef __BCPLUSPLUS__
  71. #define min(x,y)  (((x<y) ? x:y))
  72. #define max(x,y)  (((x<y) ? y:x))
  73. typedef unsigned char *PCSZ;
  74. #endif
  75.  
  76. /*+---------------------------------------------------------------------------+*/
  77. /*|   defines for some of the classic fractal types                           |*/
  78. /*+---------------------------------------------------------------------------+*/
  79.  
  80. #define MANDEL        1
  81. #define MANDELZ       "Mandelbrot"
  82. #define LAMBDA        2
  83. #define LAMBDAZ       "Lambda"
  84. #define CMPLXNEWT      3
  85. #define CMPLXNEWTZ     "Cmplx Newton"
  86. #define JULIA1        4
  87. #define JULIAZ        "Julia"
  88. #define COMPLEXMAND   5
  89. #define COMPLEXMANDZ  "Cmplx Mark's Mandelbrot"
  90. #define JULIACLICK    6   // swith to via mouse click (NOT IN MENU)
  91. //#define JULIAZ       "Julia"   already defined
  92. #define MAGNETJ1      7
  93. #define MAGNETJ1Z     "Magnetism Julia I"
  94. #define TETRATION     8
  95. #define TETRATIONZ    "Tetration"
  96. #define SPIDER        9
  97. #define SPIDERZ       "Spider"
  98.  
  99. static HWND   hwndFrame = NULLHANDLE;       // frame window handle
  100. static HWND   hwndClient = NULLHANDLE;      // client window handle
  101. static HWND   hwndMenu = NULLHANDLE;        // menu  window handle
  102. static HMQ    hmqThread2 = NULLHANDLE;      // message queue handle for thread
  103. static HPS    hpsMem = NULLHANDLE;          // for bitmap
  104. static HBITMAP hbm;
  105. static PBITMAPFILEHEADER2 pbmpfileheader2;  // now for read bitmap from file
  106. static PBITMAPINFO2 pbmp2;                  // file
  107. static HPS    hpsfile = NULLHANDLE;         // file
  108. static PBYTE  pBitsfile;                    // bitmap data from file
  109. static HBITMAP hbmfile;                     // bitmap handle
  110. static SHORT  cxClient, cyClient;           // client window X and Y size
  111. static SHORT  cxCold, cyCold;
  112. static SHORT  cxfilebmp, cyfilebmp;         // size of bmp from file
  113. static TID    tidDrawing;                   // drawing thread identifier
  114. static TID    tidSleeper;                   // sleeper thread id.             */
  115. static TID    tidColorer;
  116. static char   szAppName[ MAXNAMEL + 1 ];    // application name string
  117. static CHAR fractnamestr[40];
  118. static CHAR FullTitleText[100];            // concat of appname + fractname
  119. static  LONG rdown[256],                    // boolean for color intensity going down
  120.              gdown[256],
  121.              bdown[256];
  122.  
  123. static HPS    hpsorb;
  124. static HAB    hab = NULLHANDLE;               // PM anchor block handle
  125. static HDC    hdcMem;
  126. static PBYTE  pBitmap = NULL;                 // creater stores into this
  127. static HMTX   sema4;                          // mutex sem
  128. static HMTX   semsleeper;                     // mutex sem
  129. static HMTX   semcolorer;                     // mutex sem
  130. static PID    pidProcess;                     // process ident
  131. static APIRET semrslt;                        // result of sem op (create,.etc.)
  132. static PCSZ semname  = "\\SEM32\\STARTUP";    // name of semaphore
  133. static PCSZ sem2name = "\\SEM32\\SLEEPER";    // name of semaphore 2
  134. static PCSZ sem3name = "\\SEM32\\COLORER";    // name of semaphore 3
  135. static PBITMAPINFO2 pbmi;
  136.  
  137. static int
  138.          showorbits = 0,
  139.          colorit = 1,
  140.          changecolors = 0,
  141.          ix,
  142.          iy,
  143.          color,
  144.          insidecolor = 1,
  145.          usepotential = 0,
  146.          iter,
  147.          maxiter = 255,
  148.          maxcolor1,
  149.          maxxp,
  150.          maxyp,
  151.          periodicity,
  152.          lastperiod,
  153.          checkevery,
  154.          finiteattractor,   // we use this 'cause has own convergence criteria
  155.          fractype,
  156.          three_d = 0;
  157.  
  158. static ULONG                    // globals for remembering what menu items have checks
  159.          CurrentFractalChecked,
  160.          CurrentMapChecked,
  161.          CurrentImageOrbitsChecked,
  162.          CurrentFixChangeColorsChecked,
  163.          databytes;            // size of bitmap
  164.  
  165.  
  166. static   BOOL
  167.          CheckComplementAgain = FALSE,   // on/off toggle
  168.          spherical = FALSE,
  169.          sphere_covers_180 = FALSE,      // 180 or 360
  170.          autoscale = TRUE;
  171.  
  172.  
  173. static double
  174.          x,
  175.          y,
  176.          savedx,
  177.          savedy,
  178.          xperturb = 0.0,    // perturbations - can be applied to z, c, p...
  179.          yperturb = 0.0,
  180.          xl,               // xleft, xright,ybottom, ytop in fractal units
  181.          xr,
  182.          yb,
  183.          yt,
  184.          dx,
  185.          dy,
  186.          xlv,
  187.          xrv,
  188.          ytv,
  189.          ybv,
  190.          dxv,              // xr - xl
  191.          dyv,              // yt - yb
  192.          rmaxxp,
  193.          rmaxyp,
  194.          pixelepsilon,  // convergence criteria - name means the value is pixel/zoom based
  195.          potential,
  196.          bailout = 2.0,
  197.          maxheight,
  198.          alpha,
  199.          beta,
  200.          phi,
  201.          sa,        // sin(alpha)
  202.          ca,        // cos(alpha)
  203.          sb,        // sin(beta)
  204.          cb,        // cos(beta)
  205.          sp,        // sin(phi)
  206.          cp,        // cos(phi)
  207.      pi,
  208.          rpd,
  209.          sphererad = 1.0,
  210.          theta,
  211.          rho,
  212.          xlp, // these are the 6 min,max pts. of the zoom box in the 3-d system
  213.          xrp, // x-right-primed....
  214.          ybp,
  215.          ytp,
  216.          zbp,
  217.          ztp,
  218.          dxvp,  // xr-xl etc. but in primed (3-d rotated) coord. system
  219.          dyvp,
  220.          dzvp,
  221.          xlps,  // 3-d rotated sphere
  222.          xrps,
  223.          ybps,
  224.          ytps,
  225.          zbps,
  226.          ztps,
  227.          dxvps,
  228.          dyvps,
  229.          dzvps;
  230.  
  231. static complex
  232.          z,
  233.          c,
  234.          c0,       // constant c for Julias
  235.          savedz,   // previos z for periodicity checking
  236.          t1, t2,   // temporaries to simplify expressions
  237.          zperturb; // perturbation z
  238.  
  239. static QMSG  qmsgThread2;   // message queue
  240.  
  241. static LONG blTable[256],   // color tables
  242.             alTable[256];
  243.  
  244. /*+--------------------------------------------------------------------------+*/
  245. /*| Dummy argument parsing routine so that real one does not get linked in.  |*/
  246. /*+--------------------------------------------------------------------------+*/
  247.  
  248.  void _setuparg( void ) {}
  249.  
  250. /*+--------------------------------------------------------------------------+*/
  251. /*| Main control procedure.                                                  |*/
  252. /*+--------------------------------------------------------------------------+*/
  253.  
  254. int main( void )
  255. {
  256.    HMQ   hmq = NULLHANDLE;
  257.    ULONG flCreate = 0UL;
  258.    QMSG  qmsg;
  259.    int   rc = 1;
  260.  
  261.    do
  262.    {
  263.       // sem requests must be early on.
  264.  
  265.       semrslt = DosCreateMutexSem(semname, &sema4, 0, FALSE);
  266.       semrslt = DosRequestMutexSem(sema4, SEM_INDEFINITE_WAIT);
  267.  
  268.       semrslt = DosCreateMutexSem(sem2name, &semsleeper, 0, FALSE);
  269.       semrslt = DosRequestMutexSem(semsleeper, SEM_INDEFINITE_WAIT);
  270.  
  271.       semrslt = DosCreateMutexSem(sem3name, &semcolorer, 0, FALSE);
  272.       semrslt = DosRequestMutexSem(semcolorer, SEM_INDEFINITE_WAIT);
  273.  
  274.       // Initialize PM and create a message queue of default size.
  275.  
  276.       if ( ( hab = WinInitialize( 0UL ) ) == NULLHANDLE )
  277.          break;
  278.  
  279.       if ( ( hmq = WinCreateMsgQueue( hab, 0UL ) ) == NULLHANDLE )
  280.          break;
  281.  
  282.       // Register client window class
  283.  
  284.       if ( !WinRegisterClass( hab,          // PM anchor block handle
  285.                               WINDOW_CLASS, // window class name
  286.                           ClientWindowProc, // address of window procedure
  287.                               CS_SIZEREDRAW,// size changes cause redrawing
  288.                               0UL ) )       // window data
  289.       {
  290.          DisplayMessage( hab, IDS_NOREGISTER );
  291.          break;
  292.       }
  293.  
  294.       flCreate = FCF_STANDARD & ~FCF_TASKLIST;
  295.  
  296.       hwndFrame =
  297.          WinCreateStdWindow( HWND_DESKTOP,  // make desktop window the parent
  298.                              WS_VISIBLE,    // frame window class style
  299.                              &flCreate,     // frame control flags
  300.                              WINDOW_CLASS,  // client window class name
  301.                              "",            // title bar text
  302.                              CS_SIZEREDRAW, // client window class style
  303.                              0UL,           // resource file handle - in EXE
  304.                              ID_WINDOW,     // resources identifier
  305.                              &hwndClient ); // client window handle
  306.  
  307.       if ( hwndFrame == NULLHANDLE )
  308.       {
  309.          DisplayMessage( hab, IDS_NOSTDWINDOWS );
  310.          break;
  311.       }
  312.  
  313.       hpsorb = WinGetPS(hwndClient);    // ps for drawing orbits
  314.  
  315.       // Initialize the window title and task switch list
  316.  
  317.       InitTitle( hab, hwndFrame, szAppName, MANDELZ );
  318.  
  319.       // Create the thread that will draw the lines.
  320.  
  321.       if ( DosCreateThread( &tidDrawing, (PFNTHREAD)DrawingThread, 0UL, 0UL, STACK_SIZE ) )
  322.       {
  323.          DisplayMessage( hab, IDS_NOTHREAD );
  324.          break;
  325.       }
  326.  
  327.       if ( DosCreateThread( &tidSleeper, (PFNTHREAD)Sleeper, 0UL, 0UL, STACK_SIZE ) )
  328.       {
  329.          DisplayMessage( hab, IDS_NOTHREAD );
  330.          break;
  331.       }
  332.  
  333.       if ( DosCreateThread( &tidColorer, (PFNTHREAD)Colorer, 0UL, 0UL, STACK_SIZE ) )
  334.       {
  335.          DisplayMessage( hab, IDS_NOTHREAD );
  336.          break;
  337.       }
  338.  
  339.       // While the WM_QUIT message is not received, dispatch the message.
  340.  
  341.       while( WinGetMsg( hab, &qmsg, 0UL, 0UL, 0UL ) )
  342.          WinDispatchMsg( hab, &qmsg );
  343.       rc = 0;
  344.       break;
  345.  
  346.    }  while ( FALSE );
  347.  
  348.    if ( hwndFrame != NULLHANDLE )
  349.       WinDestroyWindow( hwndFrame );
  350.    if ( hmq != NULLHANDLE )
  351.       WinDestroyMsgQueue( hmq );
  352.    if ( hab != NULLHANDLE )
  353.       WinTerminate( hab );
  354.  
  355.    return rc;
  356. }
  357.  
  358. /*+--------------------------------------------------------------------------+*/
  359. /*        start of thread2 code                                               */
  360. /*+--------------------------------------------------------------------------+*/
  361. ixp(double x)   /* return x-pixel value given x */
  362. {
  363.         return(maxxp * (x-xlv)/dxv);
  364. }
  365.  
  366. iyp(double y)   /* return y-pixel value given y  */
  367. {
  368.         return(maxyp * (y-ybv)/dyv);
  369. }
  370.  
  371. // as above, but in primed (rotated) coord system
  372. ixpp(double x)   /* return x-pixel value given x */
  373. {
  374.         return(maxxp * (x-xlp)/dxvp);
  375. }
  376.  
  377. iypp(double y)   //
  378. {
  379.         return(maxyp * (y-ybp)/dyvp);
  380. }
  381.  
  382. izpp(double z)
  383. {
  384.         return(maxyp * (z-zbp)/dzvp);
  385. }
  386.  
  387. // as above, but now a sphere in primed (rotated) coord system
  388. ixpps(double x)   /* return x-pixel value given x */
  389. {
  390.         return(maxxp * (x-xlps)/dxvps);
  391. }
  392.  
  393. iypps(double y)   //
  394. {
  395.         return(maxyp * (y-ybps)/dyvps);
  396. }
  397.  
  398. izpps(double z)
  399. {
  400.         return(maxyp * (z-zbps)/dzvps);
  401. }
  402.  
  403. void rotpoint(double x1, double y1, double z1, double *x2, double *y2, double *z2 )
  404. {
  405.     *x2 =  x1*cb*cp - y1*cb*sp + z1*sb;
  406.     *y2 =  x1*(sa*sb*cp+sp*ca) + y1*(ca*cp-sa*sb*sp) - z1*sa*cb;
  407.     *z2 =  x1*(sa*sp-ca*sb*cp) + y1*(sa*cp+ca*sb*sp) + z1*ca*cb;
  408.     return;
  409. }
  410.  
  411. void sphericalpoint(double x1, double y1, double z1, double *x2, double *y2, double *z2)
  412. {
  413.    double rrad, trad;
  414.    double sr,cr,st,ct;
  415.    if (sphere_covers_180)
  416.       theta = (x1-xl)/dx*180.0 - 90.0;       // 180
  417.    else
  418.       theta = (x1-xl)/dx*360.0 - 180.0;      // 360
  419.    rho =   (y1-yb)/dy*180.0 - 90.0;          // +- 90
  420.    trad = theta * rpd;
  421.    rrad = rho * rpd;
  422.    cr = cos(rrad);
  423.    sr = sin(rrad);
  424.    st = sin(trad);
  425.    ct = cos(trad);
  426.    *x2 = (sphererad+z1)*cr*st;
  427.    *y2 = (-sphererad+z1)*cr*ct;
  428.    *z2 = (sphererad+z1)*sr;
  429. }
  430.  
  431. void initializechecking(void)  /* used in periodicity checking for early bailout */
  432. {
  433.    savedz = complex(0,0);
  434.    periodicity = lastperiod = 1;
  435.    checkevery = 3;
  436. }
  437.  
  438. periodicitycheck(void)
  439. {
  440.    complex dz;
  441.    dz = z - savedz;
  442.    if (abs(dz)< pixelepsilon) {
  443.      if (lastperiod==periodicity)
  444.         return periodicity;
  445.      else {
  446.         lastperiod = periodicity;
  447.         periodicity = 1;
  448.      }
  449.    }
  450.    else {
  451.      if (periodicity++ > checkevery) {
  452.         checkevery *= 2;
  453.         periodicity = 1;
  454.         savedz = z;
  455.      }
  456.    }
  457.    return 0;
  458. }
  459.  
  460.  
  461. fractalpoint(double cx, double cy, int fractype)
  462. {
  463.   POINTL ptl;
  464.   complex n,r,p,zprev,deltaz;
  465.   double arg, x2;
  466.   int ret;
  467.   iter = 0;
  468.   potential = maxheight;
  469. #ifdef PERIOD_CHECK
  470.   initializechecking();  /* look for periodicity */
  471. #endif
  472.   switch (fractype) {
  473.     case MANDEL: // mandelbrot
  474.       c = complex(cx, cy);
  475.       z = complex(xperturb,yperturb);
  476.       break;
  477.     case LAMBDA:  // lambda
  478.       c = complex(xperturb, yperturb);
  479.       z = complex(cx, cy);
  480.       break;
  481.     case JULIA1:  // julia example - no choice on 'c'
  482.       c = complex(xperturb, yperturb);
  483.       z = complex(cx, cy);
  484.       break;
  485.     case CMPLXNEWT: // complex newton
  486.       n = complex(10,3);
  487.       r = complex(xperturb, yperturb);
  488.       z = complex(cx,cy);
  489.       break;
  490.     case COMPLEXMAND: // complex mandelbrot
  491.       c = complex(cx,cy);
  492.       p = complex(xperturb, yperturb);
  493.       z = complex(0,0);
  494.       break;
  495.     case JULIACLICK: // switch to Julia via mouse click
  496.       z = complex(cx, cy);   // note - we already have c0 from mouse click pos
  497.       break;
  498.     case MAGNETJ1:
  499.       c = complex(xperturb, yperturb);
  500.       z = complex(cx, cy);
  501.       break;
  502.     case TETRATION:
  503.       z = complex(cx, cy);
  504.       c = z;
  505.     break;
  506.     case SPIDER :
  507.       z = complex(cx,cy);
  508.       c = z;
  509.     break;
  510.   default :
  511.       break;
  512.   } // end switch
  513.   while (iter < maxiter) { // iteration loop starts here
  514.     switch (fractype) {
  515.       case MANDEL:
  516.         z = z*z + c;
  517.         break;
  518.       case LAMBDA:
  519.         z = c*z*(1.0-z);
  520.         break;
  521.       case JULIA1:
  522.         z = z*z + c;
  523.         break;
  524.       case CMPLXNEWT:
  525.         zprev = z;
  526.         z = ((n-1.0)*pow(z,n)+r)/(n*pow(z,n-1));
  527.         deltaz = z - zprev;
  528.         break;
  529.       case COMPLEXMAND:
  530.         z = z*z*pow(c,p-1) + c;
  531.         break;
  532.       case JULIACLICK:  // switch to Julia
  533.         z = z*z + c0;
  534.         break;
  535.       case MAGNETJ1:
  536.         t1 = z*z+c-1.0;
  537.         t1 = t1*t1;
  538.         t2 = 2.0*z+c-2.0;
  539.         t2 = t2*t2;
  540.         z = t1/t2;
  541.         break;
  542.       case TETRATION:
  543.         z = pow(c,z);
  544.         break;
  545.       case SPIDER :
  546.         z = z*z + c;
  547.         c = c/2.0 + z;
  548.         break;
  549.       default:
  550.         break;
  551.     } // end switch
  552.     if ((showorbits) && (iter>0)) {
  553.        x = real(z);
  554.        y = imag(z);
  555.        ptl.x = (x-xlv)/dxv*maxxp;
  556.        ptl.y = (y-ytv)/dyv*rmaxyp+rmaxyp;
  557.        GpiMove(hpsorb,&ptl);
  558.        GpiSetColor(hpsorb, iter%maxcolor1);
  559.        GpiSetPel(hpsorb, &ptl);
  560.     }
  561.     iter++;
  562. #ifdef PERIOD_CHECK             // can't check periodicity with finit attracters
  563.     if ((iter % checkevery == 0) && (!finiteattractor) && (!usepotential)) {
  564.         if (periodicitycheck())
  565.            return insidecolor;
  566.      }
  567. #endif
  568.     if (finiteattractor) {
  569.         if ( abs(deltaz) <  pixelepsilon)
  570.            return iter % maxcolor1;
  571.      }
  572.      else {
  573.        if (abs(z) > bailout) {
  574.           if (usepotential) {
  575.              //potential = maxcolor1*(1.0-log(abs(z))/pow(2.0, iter));
  576.              arg = min(abs(z)/bailout, 1.0);
  577.              potential = maxcolor1*(1.0-log(arg));
  578.              ret = (int)ceil(potential) % maxcolor1;
  579.           }
  580.           else
  581.             ret = iter % maxcolor1;
  582.          return ret;
  583.        }
  584.     }
  585.   } // end while
  586.   return insidecolor;
  587. }
  588.  
  589.  
  590. void fractalx(void)
  591. {
  592.    /* - this operates on x. (does one y-line then checks msgs) -*/
  593.       double
  594.          cx,
  595.          cy,
  596.          cxparam,
  597.          cyparam,
  598.          czparam,
  599.          xprime,
  600.          yprime,
  601.          zprime;  // 3-D rotated pts.  Do Not confuse with type complex
  602.       POINTL
  603.          ptl;
  604.       int
  605.          xpixel,
  606.          ypixel,
  607.          pinx;
  608.       PBYTE  pBitmaptemp,         // aviod excessive indexing
  609.              pBitmapditherup,     // needs dithering both directions, highly non-linear
  610.              pBitmapditherahead;
  611.       maxxp = cxClient-1;
  612.       maxyp = cyClient-1;
  613.       rmaxxp = (double) maxxp;
  614.       rmaxyp = (double) maxyp;
  615.       xl = xlv;
  616.       xr = xrv;
  617.       yb = ybv;
  618.       yt = ytv;
  619.       dx = xr - xl;
  620.       dxv = xrv - xlv;
  621.       dyv = ytv - ybv;
  622.       if (!spherical)
  623.          dy = yt - yb;
  624.       else
  625.       {
  626.           // use this for square squares, round spheres, etc.
  627.           dy = dx * rmaxyp / rmaxxp;
  628.           yt = dy/2.0;
  629.           yb = -yt;
  630.       }
  631.       pixelepsilon = dx/(2.0*rmaxxp);    // ref. Bert Tyler - the 2.0 is from 1/2 pixel
  632.       cy = ytv + (double)(iy - maxyp) * dyv/rmaxyp;
  633.       ix = 0;
  634.       finiteattractor = (fractype == CMPLXNEWT);  // or in some more if needed
  635.       while (ix <= maxxp) {
  636.           cx = dxv * (double) ix/rmaxxp + xlv;
  637.           color = fractalpoint(cx, cy, fractype);
  638.           // cxparam, etc, are cx, etc. for switched co-ord systems.
  639.           cxparam = dx * (double) ix/rmaxxp + xl;
  640.           cyparam = yt + (double)(iy-maxyp) * dy/rmaxyp;
  641.  
  642.           if ((three_d) && (!spherical)) {
  643.                if (usepotential)
  644.                   czparam = potential/maxheight;
  645.                else
  646.                   czparam = (double) color/maxheight;
  647.                rotpoint(cxparam, cyparam, czparam, &xprime, &yprime, &zprime);
  648.                if (autoscale) {
  649.                   xpixel = ixpp(xprime);
  650.                   ypixel = izpp(zprime);
  651.                }
  652.                else {
  653.                   xpixel = ixp(xprime);
  654.                   ypixel = iyp(zprime);
  655.                }
  656.                pinx = xpixel + cxClient*ypixel;
  657.                pBitmaptemp = &pBitmap[pinx];         // saves on index op (below)
  658.                if ((xpixel > 0) && (xpixel < maxxp)   // prevent an access violation
  659.                     && (ypixel > 0) && (ypixel < maxyp)
  660.                     && (*pBitmaptemp == 0) )  // this line for ray tracing
  661.                           *pBitmaptemp = (UCHAR) color;
  662.           }
  663.           if (spherical) {
  664.                if (usepotential)
  665.                   czparam = potential/maxheight*sphererad/10.0;    // cut by 1/10 if spherical
  666.                else
  667.                   czparam = (double) color/maxheight*sphererad/10.0;
  668.               sphericalpoint(cxparam, cyparam, czparam, &xprime, &yprime, &zprime);
  669.               if (three_d)
  670.                   rotpoint(xprime, yprime, zprime, &xprime, &yprime, &zprime);
  671.               if (yprime <= 0.0) { // show near side only
  672.                   if (autoscale) {
  673.                       xpixel = ixpps(xprime);
  674.                       ypixel = izpps(zprime);
  675.                   }
  676.                   else {
  677.                       xpixel = ixp(xprime);
  678.                       ypixel = iyp(zprime);
  679.                   }
  680.                   // since another thread could be allocating/deallocating the
  681.                   // bitmap array, it must be protected. A mutex sem would probably
  682.                   // be too expensive just to protect an index-store type op.
  683.                   DosEnterCritSec();
  684.                   pinx = xpixel + cxClient*ypixel;
  685.                   pBitmaptemp = &pBitmap[pinx];
  686.                   pBitmapditherahead = pBitmaptemp;
  687.                   pBitmapditherup = pBitmaptemp;
  688.                   if ((xpixel > 0) && (xpixel < maxxp)   // prevent an access violation
  689.                        && (ypixel > 0) && (ypixel < maxyp) )
  690.                            *pBitmaptemp = (UCHAR) color;
  691.  
  692.                   // now dither twice - both up and ahead
  693.                   if ((xpixel > 0) && (xpixel < maxxp)
  694.                        && (ypixel+2 > 0) && (ypixel+2 < maxyp))  // up
  695.                   {
  696.                             pBitmapditherup += cxClient;
  697.                            *pBitmapditherup = (UCHAR) color;
  698.                             pBitmapditherup += cxClient;
  699.                            *pBitmapditherup = (UCHAR) color;
  700.                   }
  701.                   if ((xpixel+2 > 0) && (xpixel+2 < maxxp)      // ahead
  702.                        && (ypixel > 0) && (ypixel < maxyp))
  703.                   {
  704.                             pBitmapditherahead++;
  705.                            *pBitmapditherahead = (UCHAR) color;
  706.                             pBitmapditherahead++;
  707.                            *pBitmapditherahead = (UCHAR) color;
  708.                   }
  709.                   DosExitCritSec();
  710.               } // end if y<=0
  711.            }
  712.            if ((!spherical) && (!three_d)) {
  713.              DosEnterCritSec();
  714.              // several things could happen here. cxClient, cyClient could change,
  715.              // and the bitmap array could be de-allocated.
  716.              if ((ix < cxClient) && (iy < cyClient))
  717.                pBitmap[ix+cxClient*iy] = color;
  718.              DosExitCritSec();
  719.            }
  720.           ix++;
  721.       } // end while(ix..)
  722.       iy++;
  723.       if (iy > maxyp)
  724.         iy = 0;
  725.       return;
  726. }
  727.  
  728. /*+--------------------------------------------------------------------------+*/
  729. /*| DrawingThread - Procedure that draws in the client window.               |*/
  730. /*+--------------------------------------------------------------------------+*/
  731.  
  732. static void DrawingThread( void )
  733. {
  734.    HAB   habThread2 = NULLHANDLE;           /* anchor block handle for thread */
  735.    HPS   hps = NULLHANDLE;                  /* presentation Space handle      */
  736.    RECTL rclClient;                         /* rectangle for client window    */
  737.  
  738.    int ci, i;
  739.  
  740.    // Change the priority class of this thread
  741.    // PRTYC_REGULAR, PRTYC_IDLETIME, PRTYC_TIMECRITICAL, PRTYC_NOCHANGE
  742.    DosSetPriority( PRTYS_THREAD, PRTYC_IDLETIME, 0L, 0UL );
  743.  
  744.    habThread2 = WinInitialize( 0UL );
  745.    hmqThread2 = WinCreateMsgQueue( habThread2, 0UL );
  746.  
  747.    hps = WinGetPS( hwndClient );
  748.  
  749.    GpiSavePS(hps);
  750.  
  751.    semrslt = DosRequestMutexSem(sema4, SEM_INDEFINITE_WAIT);
  752.    semrslt = DosReleaseMutexSem(sema4);
  753.  
  754.    qmsgThread2.msg = WM_PAINT;  // value = anything != WM_USER_END_THREAD
  755.  
  756.    /* Run fractal line (y=const) in thread2, then check msgs  */
  757.  
  758.    while ( qmsgThread2.msg != WM_USER_END_THREAD )  {
  759.         fractalx();
  760.         WinPeekMsg( habThread2, &qmsgThread2, NULLHANDLE, 0UL, 0UL, PM_REMOVE );
  761.    }
  762.  
  763.    /* Clean up and terminate drawing thread. */
  764.  
  765.    GpiRestorePS(hps, -1L);
  766.    WinReleasePS( hps );
  767.    WinReleasePS(hpsorb);
  768.    WinDestroyMsgQueue( hmqThread2 );
  769.    WinTerminate( habThread2 );
  770.    DosExit( EXIT_THREAD, 0UL );
  771. }
  772.  
  773. /*+--------------------------------------------------------------------------+*/
  774. /*            End of thread2                                                 +*/
  775. /*+--------------------------------------------------------------------------+*/
  776.  
  777. /*---------------------------------------------------------------------------+*/
  778. /*            Start of threads 3 & 4                                         */
  779. /*+--------------------------------------------------------------------------+*/
  780.  
  781. static void Sleeper(void) /* #3 */
  782. {
  783.    semrslt = DosRequestMutexSem(semsleeper, SEM_INDEFINITE_WAIT);
  784.    semrslt = DosReleaseMutexSem(semsleeper);
  785.    while(1) {
  786.        DosSleep(3000);
  787.        WinInvalidateRect(hwndClient, NULL, FALSE);
  788.    }
  789. }
  790.  
  791. static void Colorer(void) /* #4 */
  792. {
  793.    int i;
  794.    LONG r,g,b, rswitch, gswitch, bswitch;
  795.  
  796. // these are delta colors that get added or subtracted to the rgb table entries.
  797. // They are small prime numbers to defer periodicity. You could think of them
  798. // as causing traveling waves up and down the table and traveling at different speeds.
  799. #define   dr  3
  800. #define   dg  5
  801. #define   db  7
  802.  
  803.    semrslt = DosRequestMutexSem(semcolorer, SEM_INDEFINITE_WAIT);
  804.    semrslt = DosReleaseMutexSem(semcolorer);
  805.    while(1) {
  806.        DosSleep(2523);  // weird number just so won't get harmonic with Sleeper thread
  807.        if (changecolors) {
  808.              for (i=1; i<maxcolor1; i++) {
  809.                    r = (blTable[i] & 0x00ff0000) >> 16;
  810.                    g = (blTable[i] & 0x0000ff00) >> 8;
  811.                    b = (blTable[i] & 0x000000ff);
  812.  
  813.                    rswitch = ((r >= 255-dr) & !rdown[i]) | ((r <= dr) & rdown[i]);
  814.                    gswitch = ((g >= 255-dg) & !gdown[i]) | ((g <= dg) & gdown[i]);
  815.                    bswitch = ((b >= 255-db) & !bdown[i]) | ((b <= db) & bdown[i]);
  816.  
  817.                    if (rswitch) rdown[i] = !rdown[i];
  818.                    if (gswitch) gdown[i] = !gdown[i];
  819.                    if (bswitch) bdown[i] = !bdown[i];
  820.  
  821.                    if (rdown[i]) r-=dr-1; else r+=dr;
  822.                    if (gdown[i]) g-=dg-1; else g+=dg;
  823.                    if (bdown[i]) b-=db-1; else b+=db;
  824.  
  825.                    blTable[i] = (r<<16) + (g<<8) + b;
  826.  
  827.              }
  828.        }// end if
  829.    } // end while
  830. }
  831.  
  832.  
  833. /*+--------------------------------------------------------------------------+*/
  834. /*            End of threads 3 & 4                                           +*/
  835. /*+--------------------------------------------------------------------------+*/
  836.  
  837. /*---------------------------------------------------------------------------+*/
  838. /*          Back to thread1                                                   */
  839. /*+--------------------------------------------------------------------------+*/
  840.  
  841. /*+--------------------------------------------------------------------------+*/
  842. /*| InitTitle - Initializes window title and task switch list.               |*/
  843. /*+--------------------------------------------------------------------------+*/
  844.  
  845.  
  846. static void InitTitle( HAB hab, HWND hwnd, char *szTitle, char *fractname )
  847. {
  848.    SWCNTRL tSwcntrl;                        /* task switch structure          */
  849.  
  850.    /* Load the application name from the resources in the EXE.  Set the title */
  851.    /* bar text to this name.  Then add this application to the task manager   */
  852.    /* list with the loaded application name.                                  */
  853.  
  854.    WinLoadString( hab, 0UL, IDS_APPNAME, MAXNAMEL, szTitle );
  855.    UpdateTitle(hwnd, szTitle, fractname);
  856.  
  857.    tSwcntrl.hwnd = hwnd;
  858.    tSwcntrl.hwndIcon = NULLHANDLE;
  859.    tSwcntrl.hprog = NULLHANDLE;
  860.    tSwcntrl.idProcess = 0;
  861.    tSwcntrl.idSession = 0;
  862.    tSwcntrl.uchVisibility = SWL_VISIBLE;
  863.    tSwcntrl.fbJump = SWL_JUMPABLE;
  864.    strcpy( tSwcntrl.szSwtitle, szTitle );
  865.    tSwcntrl.bProgType = PROG_PM;
  866.    WinAddSwitchEntry( &tSwcntrl );
  867.  
  868.    return;
  869. }
  870.  
  871. static void UpdateTitle(HWND hwnd, char * szAppName, char * fractname)
  872. {
  873.     strcpy(FullTitleText, szAppName);
  874.     strcat(FullTitleText, " - ");
  875.     strcat(FullTitleText, fractname);
  876.     WinSetWindowText(hwnd, FullTitleText);
  877. }
  878.  
  879. BOOL GetFileName(ULONG WichDialog, char szFullPath[])
  880. {
  881.     FILEDLG
  882.          fdlg;
  883.  
  884.     fdlg.cbSize = sizeof(FILEDLG);       // Size of FILEDLG structure.
  885.                                          // FDS_ flags. Alter behavior of dlg.
  886.                                          //   FDS_SAVEAS_DIALOG or FDS_OPEN_DIALOG
  887.                                          //   are args to this func
  888.     fdlg.fl =  WichDialog | FDS_ENABLEFILELB;
  889.     fdlg.ulUser = 0;                     // User defined field.
  890.     fdlg.lReturn = 0;                    // Result code from dialog dismissal.
  891.     fdlg.lSRC = 0;                       // System return code.
  892.     fdlg.pszTitle = NULL;                // String to display in title bar.
  893.     fdlg.pszOKButton = NULL;             // String to display in OK button.
  894.                                          // Entry point to custom dialog proc.
  895.     fdlg.pfnDlgProc = (PFNWP)NULL;
  896.     fdlg.pszIType = NULL;                // Pointer to string containing
  897.                                          //   initial EA type filter. Type
  898.                                          //   does not have to exist in list.
  899.     fdlg.papszITypeList = NULL;          // Pointer to table of pointers that
  900.                                          //   point to null terminated Type
  901.                                          //   strings. End of table is marked
  902.                                          //   by a NULL pointer.
  903.     fdlg.pszIDrive = NULL;               // Pointer to string containing                                         //   initial drive. Drive does not
  904.                                          //   have to exist in drive list.
  905.     fdlg.papszIDriveList = NULL;         // Pointer to table of pointers that
  906.                                          //   point to null terminated Drive
  907.                                          //   strings. End of table is marked
  908.                                          // by a NULL pointer.
  909.     fdlg.hMod = (HMODULE)0;              // Custom File Dialog template.
  910.     strcpy(fdlg.szFullFile, "*.BMP"); // Initial or selected fully
  911.                                          //   qualified path and file.
  912.     fdlg.papszFQFilename = NULL;         // Pointer to table of pointers that
  913.                                          //   point to null terminated FQFname
  914.                                          //   strings. End of table is marked
  915.                                          //   by a NULL pointer.
  916.     fdlg.ulFQFCount = 0;                 // Number of files selected
  917.     fdlg.usDlgId = 0;                    // Custom dialog id.
  918.     fdlg.x = 0;                          // X coordinate of the dialog
  919.     fdlg.y = 0;                          // Y coordinate of the dialog
  920.     fdlg.sEAType = 0;                    // Selected file's EA Type.
  921.  
  922.     // call up file dialog
  923.     if (!WinFileDlg(HWND_DESKTOP, hwndClient, (PFILEDLG)&fdlg))
  924.         return TRUE;
  925.  
  926.     if (fdlg.lReturn != DID_OK)
  927.         return TRUE;
  928.  
  929.     strcpy(szFullPath, fdlg.szFullFile);
  930.  
  931.     return FALSE;  // aok
  932.  
  933. } // End of GetFileName()
  934.  
  935. VOID DrawBoxOutline(HWND hwnd, POINTL *pptlStart, POINTL *pptlEnd)
  936. {
  937.      HPS hps;
  938.  
  939.      hps = WinGetPS(hwnd);
  940.      GpiSetMix(hps, FM_INVERT);
  941.      GpiMove(hps, pptlStart);
  942.      GpiBox(hps, DRO_OUTLINE, pptlEnd, 0L, 0L);
  943.      WinReleasePS(hps);
  944. }
  945.  
  946.  
  947. LoadColorTable(char *fn, LONG *cTable, int maxcolor1)
  948. {
  949.   FILE *fin;
  950.   int
  951.         index,
  952.         count,
  953.         red,
  954.         green,
  955.         blue;
  956. #ifdef __BCPLUSPLUS__
  957. const  char  *openmode = "rt";
  958. #else
  959. const  char  *openmode = "r";
  960. #endif
  961.  
  962.   #define MAXLINELENGTH 90
  963.   char line[MAXLINELENGTH];
  964.   if ( (fin=fopen(fn, openmode)) == NULL)
  965.      return 1;
  966.  
  967.   index = 0;
  968.   while (index < maxcolor1) {
  969.       if (fgets(line, MAXLINELENGTH,fin) == NULL) {
  970.           fclose(fin);
  971.           return 1;
  972.       }
  973.       count = sscanf(line,"%d %d %d %d",&red, &green, &blue);
  974.       if (count < 3) {
  975.          fclose(fin);
  976.          return 1;
  977.       }
  978.        cTable[index] = ((red & 0xff) << 16) +
  979.                        ((green & 0xff) << 8) +
  980.                         (blue & 0xff);
  981.        index++;
  982.   }
  983.   fclose(fin);
  984.   if (index < maxcolor1)
  985.      return 1;
  986.   return 0;
  987. }
  988.  
  989. VOID LoadColors(char *fn, LONG* blTable, int maxcolor1)
  990. {
  991.     int i;
  992.  
  993.     if (LoadColorTable(fn, blTable, maxcolor1)) { //  if fails, make it random
  994.          blTable[0] = 0;
  995.          for (i=1; i<maxcolor1; i++)
  996.          {
  997.           blTable[i] = ((rand() & 0xff) << 16) +
  998.                        ((rand() & 0xff) << 8) +
  999.                         (rand() & 0xff);
  1000.  
  1001.           }
  1002.     }
  1003. }
  1004.  
  1005. VOID CheckMenu(ULONG id, BOOL fCheck)
  1006. {
  1007.     WinSendMsg(hwndMenu,                //global main menu handle
  1008.        MM_SETITEMATTR,                  // set menu attribute
  1009.        MPFROM2SHORT(id, TRUE),          //menu id
  1010.        MPFROM2SHORT(MIA_CHECKED,        // mask = check bit
  1011.        fCheck ? MIA_CHECKED : ~MIA_CHECKED));    // turn on/off
  1012.  
  1013. }   /* end CheckMenu() */
  1014.  
  1015. VOID SwitchCheck(ULONG id, ULONG *CurrentId)
  1016. {
  1017.     CheckMenu(*CurrentId, FALSE);   // uncheck prev.
  1018.     CheckMenu(id, TRUE);            // check this one
  1019.     *CurrentId = id;
  1020. }
  1021.  
  1022. SaveAsBitmap(VOID)
  1023. {
  1024. #define  OPEN_FILE    0x01
  1025. #define  CREATE_FILE  0x10
  1026. #define  FILE_ARCHIVE 0x20
  1027. #define  FILE_EXISTS  OPEN_FILE
  1028. #define  FILE_NOXISTS CREATE_FILE
  1029. #define  DASD_FLAG    0
  1030. #define  INHERIT      0x80
  1031. #define  WRITE_THRU   0
  1032. #define  FAIL_FLAG    0
  1033. #define  SHARE_FLAG   0x10
  1034. #define  ACCESS_FLAG  0x02
  1035. #define  FILE_ATTRIBUTE FILE_ARCHIVE
  1036.  
  1037.     CHAR               FileName[256];
  1038.     ULONG               Wrote0, Wrote1, Wrote2;
  1039.     ULONG               Action;
  1040.     ULONG               FileHeaderSize;
  1041.     ULONG               BmpHeaderSize;
  1042.     ULONG               RGBTableSize;
  1043.     LONG                lScansReturned;
  1044.     HFILE               FileHandle;
  1045.     APIRET              rc;
  1046.     BITMAPFILEHEADER2   FileHeader;
  1047.     PBITMAPINFO2        pbmi2InfoTable;
  1048.     PBYTE               pBuff;   // copy of bitmap
  1049.  
  1050.  
  1051.     FileHeaderSize = sizeof(BITMAPFILEHEADER2);
  1052.     BmpHeaderSize = sizeof(BITMAPINFOHEADER2);
  1053.     RGBTableSize = maxcolor1 * sizeof(RGB2);
  1054.  
  1055.     // build the file header
  1056.     FileHeader.usType = (USHORT) BFT_BMAP;
  1057.     FileHeader.cbSize = sizeof(BITMAPFILEHEADER2) + RGBTableSize + databytes;
  1058.     FileHeader.offBits = sizeof(BITMAPFILEHEADER2) + RGBTableSize;
  1059.  
  1060.     while (1)
  1061.     {
  1062.         if (GetFileName(FDS_SAVEAS_DIALOG, FileName))
  1063.            return 1; // fail or DID_CANCEL
  1064.  
  1065.         DosAllocMem((PPVOID)&pbmi2InfoTable,
  1066.                              sizeof(BITMAPINFOHEADER2) + RGBTableSize,
  1067.                              PAG_COMMIT | PAG_READ | PAG_WRITE);
  1068.         DosAllocMem((PPVOID)&pBuff,
  1069.                              databytes,
  1070.                              PAG_COMMIT | PAG_READ | PAG_WRITE);
  1071.  
  1072.         // these must be initted
  1073.         pbmi2InfoTable->cbFix = sizeof(BITMAPINFOHEADER2);
  1074.         pbmi2InfoTable->cPlanes = pbmi->cPlanes;
  1075.         pbmi2InfoTable->cBitCount = pbmi->cBitCount;
  1076.         pbmi2InfoTable->ulCompression = BCA_UNCOMP;
  1077.         pbmi2InfoTable->usReserved = 0;
  1078.         pbmi2InfoTable->usRecording = BRA_BOTTOMUP;
  1079.         pbmi2InfoTable->usRendering = BRH_NOTHALFTONED;
  1080.         pbmi2InfoTable->ulColorEncoding = BCE_RGB;
  1081.         // now put it the current RGB table
  1082.         memcpy(&pbmi2InfoTable->ulIdentifier+sizeof(ULONG), blTable, RGBTableSize);
  1083.  
  1084.         lScansReturned = GpiQueryBitmapBits( hpsMem,
  1085.                                              0L,         // lScanStart
  1086.                                              cyClient,   // lScans
  1087.                                              pBuff,
  1088.                                              pbmi2InfoTable);
  1089.         if (lScansReturned == 0)
  1090.           break;
  1091.  
  1092.         rc = DosOpen ( FileName,
  1093.                        &FileHandle,
  1094.                        &Action,
  1095.                        FileHeaderSize + RGBTableSize + databytes,
  1096.                        FILE_ATTRIBUTE,
  1097.                        OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_FAIL_IF_EXISTS,
  1098.                        DASD_FLAG | INHERIT | SHARE_FLAG | ACCESS_FLAG,
  1099.                        0L);
  1100.         if (rc)
  1101.           break;
  1102.  
  1103.         rc = DosWrite( FileHandle,
  1104.                        (PVOID) (&FileHeader),
  1105.                        FileHeaderSize - BmpHeaderSize,  // cause they are in sep locations
  1106.                        &Wrote0);
  1107.         if (rc)
  1108.            break;
  1109.         rc = DosWrite( FileHandle,
  1110.                        (PVOID) pbmi2InfoTable,
  1111.                        BmpHeaderSize + RGBTableSize,  // cause they are in sep locations
  1112.                        &Wrote0);
  1113.         if (rc)
  1114.            break;
  1115.  
  1116.  
  1117.         rc = DosWrite( FileHandle,
  1118.                        pBuff,     //pBitmap
  1119.                        databytes,
  1120.                        &Wrote2);
  1121.         if (rc)
  1122.           break;
  1123.  
  1124.  
  1125.         rc = DosClose(FileHandle);
  1126.  
  1127.         if (rc)
  1128.           break;
  1129.  
  1130.         DosFreeMem(pbmi2InfoTable);
  1131.         DosFreeMem(pBuff);
  1132.  
  1133.         return 0; // passed
  1134.  
  1135.     } // end while (1)
  1136.  
  1137.     return 1;   // failed
  1138. }
  1139.  
  1140. LoadFractalBitmap(VOID)
  1141. {
  1142. #define  EABUF        0L
  1143.     CHAR              FileName[256];
  1144.     FILESTATUS3        filestatus3;
  1145.     ULONG              cBytes;
  1146.     ULONG              cbImageData;
  1147.     APIRET             rc;
  1148.     ULONG              Action;
  1149.     HFILE              FileHandle;
  1150.     SWP                winpos;
  1151.     LONG               lScansReturned;
  1152.     BITMAPINFOHEADER2  bmp;
  1153.  
  1154.     while(1)
  1155.     {
  1156.         if (GetFileName(FDS_OPEN_DIALOG, FileName))
  1157.                return 1; // fail or DID_CANCEL
  1158.  
  1159.         rc = DosOpen ( FileName,
  1160.                        &FileHandle,
  1161.                        &Action,
  1162.                        0L,
  1163.                        FILE_ATTRIBUTE,
  1164.                        OPEN_ACTION_OPEN_IF_EXISTS,
  1165.                        DASD_FLAG | INHERIT | SHARE_FLAG | ACCESS_FLAG,
  1166.                        0L);
  1167.         if (rc)
  1168.            break;
  1169.         rc = DosQueryFileInfo(FileHandle, FIL_STANDARD,
  1170.                                    (PVOID)&filestatus3, sizeof( filestatus3 ));
  1171.         // alloc memory for entire bitmap file read
  1172.         DosAllocMem((PPVOID)&pbmpfileheader2,
  1173.                              filestatus3.cbFile,
  1174.                              PAG_COMMIT | PAG_READ | PAG_WRITE);
  1175.         rc = DosRead( FileHandle, (PVOID)pbmpfileheader2, filestatus3.cbFile, &cBytes );
  1176.         if( rc != 0  ||  cBytes == 0 )
  1177.         {
  1178.            free( pbmpfileheader2 );
  1179.            DosClose( FileHandle );
  1180.            //WinPostMsg( hwndToAck, WM_NACK_FILE_READING_ERROR,
  1181.            //               (MPARAM)msg, (MPARAM)0L );
  1182.            return 1;
  1183.         }
  1184.         DosClose( FileHandle );
  1185.         // set pbmp2 to point to the BITMAPINFO2 structure within the file
  1186.         pbmp2 = (PBITMAPINFO2)(&pbmpfileheader2->bmp2);
  1187.         pBitsfile = (PBYTE)pbmpfileheader2 + pbmpfileheader2->offBits;
  1188.  
  1189.         cxfilebmp = pbmp2->cx;   //need these as globals
  1190.         cyfilebmp = pbmp2->cy;
  1191.  
  1192.         return 0;   // pass
  1193.     }
  1194.     return 1;    // fail
  1195. }
  1196.  
  1197. /*+--------------------------------------------------------------------------+*/
  1198. /*| ClientWindowProc - Client window procedure.                              |*/
  1199. /*+--------------------------------------------------------------------------+*/
  1200.  
  1201. static MRESULT EXPENTRY ClientWindowProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2 )
  1202. {
  1203.    HPS                       hps = NULLHANDLE;    /* presentation space handle      */
  1204.    int                       killer;
  1205.    int                       i;
  1206.    USHORT red,
  1207.           blue,
  1208.           green;
  1209.  
  1210.    static BOOL               fCapture, fShowBox;
  1211.    static POINTL             ptlStart, ptlEnd, ptlBoxStart, ptlBoxEnd;
  1212.  
  1213.    /* params for WinDrawBitmap */
  1214.    RECTL                     rectl;
  1215.  
  1216.    int                       ixl, ixr, iyb, iyt, temp;
  1217.  
  1218.    /* stuff for bitmap draws */
  1219.    static HDC                hdcMem;
  1220.    static HDC                hdcMemfile;
  1221.    PSZ                       pszData[4] = {"Display", NULL, NULL, NULL};
  1222.    SIZEL                     sizlPage = {0, 0};
  1223.    SIZEL                     sizlFilePage = {0, 0};
  1224.    static BITMAPINFOHEADER2  bmp;
  1225.    static HBITMAP            hbmOld;
  1226.  
  1227.    POINTL                    aptl[4];
  1228.    POINTL                    textat;
  1229.    POINTL                    aptflFile[4];
  1230.    LONG                      rc;
  1231.  
  1232.    LONG                      alData[2];
  1233.    LONG                      ix0, iy0;
  1234.    double                    cx0, cy0;
  1235.  
  1236.    PID                       pidowner;
  1237.    TID                       tidowner;
  1238.    ULONG                     claimcount;
  1239.  
  1240.    static ULONG              headerbytes;
  1241.    SWP swp;
  1242.  
  1243.    switch( msg )
  1244.    {
  1245.       case WM_CREATE:
  1246.           //The client window has been created but is not visible yet.
  1247.           // Initialize the window here. Also, set up device context, etc.,
  1248.  
  1249.           hwndMenu = WinWindowFromID( WinQueryWindow( hwnd, QW_PARENT),
  1250.                                       FID_MENU);
  1251.  
  1252.           hdcMem = DevOpenDC(hab, OD_MEMORY, "*", 4, (PDEVOPENDATA) pszData, NULLHANDLE);
  1253.  
  1254.           hpsMem = GpiCreatePS(hab, hdcMem, &sizlPage, PU_PELS | GPIT_MICRO | GPIA_ASSOC );
  1255.  
  1256.           DevQueryCaps(hdcMem, CAPS_COLORS, 256L, alTable);
  1257.           maxcolor1 = alTable[0];
  1258.           maxheight = (double) (maxcolor1 + maxcolor1/5);
  1259.  
  1260.           hps = WinGetPS(hwnd);
  1261.  
  1262.           GpiQueryLogColorTable(hps, 0L, 0L, maxcolor1, blTable);  /*-- what's loaded */
  1263.  
  1264.           headerbytes = (ULONG)sizeof(BITMAPINFOHEADER2) + maxcolor1*sizeof(RGB2);
  1265.  
  1266.           DosAllocMem((PPVOID)&pbmi, headerbytes, PAG_COMMIT | PAG_READ | PAG_WRITE);
  1267.  
  1268.           LoadColors(".\\DEFAULT.MAP", blTable, maxcolor1);
  1269.  
  1270.           //GpiQueryRealColors(hps, 0, 16L, maxcolor1-16L, blTable); // physical device table
  1271.           blTable[0] = 0;    // must be black
  1272.           GpiCreateLogColorTable(hps, 0L, LCOLF_CONSECRGB, 0L, maxcolor1, blTable);
  1273.           WinReleasePS(hps);
  1274.  
  1275.           // initialize size of fractal window in real x,y coords. also iy
  1276.           iy = 0;
  1277.           xlv = -2.5;
  1278.           xrv = 1.5;
  1279.           ybv = -1.5;
  1280.           ytv = 1.5;
  1281.           dxv = xrv - xlv;
  1282.           fractype = MANDEL;  // initial default
  1283.           strcpy(fractnamestr, MANDELZ);
  1284.           CurrentFractalChecked = IDM_MANDEL;
  1285.           CurrentMapChecked = IDM_DEFAULT;
  1286.           CurrentImageOrbitsChecked = IDM_IMAGE;
  1287.           CurrentFixChangeColorsChecked = IDM_FIXCOLORS;
  1288.           three_d = 0;
  1289.           spherical = FALSE;
  1290.           usepotential = 0;
  1291.       pi = M_PI;
  1292.       rpd = pi/180.0;
  1293.           alpha = 20.0;
  1294.           beta = 10.0;
  1295.           phi = 10.0;
  1296.       sa = sin(alpha*rpd);
  1297.       ca = cos(alpha*rpd);
  1298.       sb = sin(beta*rpd);
  1299.       cb = cos(beta*rpd);
  1300.           sp = sin(phi*rpd);
  1301.           cp = cos(phi*rpd);
  1302.  
  1303.           break;
  1304.  
  1305.       case WM_SIZE:
  1306.          /* Window is being resized so get new client window size  */
  1307.          hps = WinGetPS(hwnd);
  1308.  
  1309.          cxCold = cxClient;
  1310.          cyCold = cyClient;
  1311.          cxClient = (((LOUSHORT( mp2 )+7)/8)*8);    /* Get new client window size     */
  1312.          cyClient = (((HIUSHORT( mp2 )+7)/8)*8);    /* has to be 32-bit word alligned */
  1313.  
  1314.           // make cx even # of words * 4 bytes/word * height * number of color planes
  1315.           if (pBitmap != NULL)
  1316.              DosFreeMem(pBitmap);
  1317.           databytes = (cxClient+1+31)/32*4*cyClient*8;
  1318.           DosAllocMem((PPVOID)&pBitmap, databytes, PAG_COMMIT | PAG_READ | PAG_WRITE);
  1319.  
  1320.          // determine the device's plane/bit count format
  1321.          GpiQueryDeviceBitmapFormats(hpsMem, 2, alData);
  1322.  
  1323.           bmp.cbFix           = (ULONG)sizeof(BITMAPINFOHEADER2);
  1324.           bmp.cx              = cxClient;
  1325.           bmp.cy              = cyClient;
  1326.           bmp.cPlanes         = alData[0];
  1327.           bmp.cBitCount       = alData[1];
  1328.           bmp.ulCompression   = BCA_UNCOMP;
  1329.           bmp.cbImage         = cxClient;
  1330.           bmp.cxResolution    = 70;
  1331.           bmp.cyResolution    = 70;
  1332.           bmp.cclrUsed        = maxcolor1;
  1333.           bmp.cclrImportant   = 0;
  1334.           bmp.usUnits         = BRU_METRIC;
  1335.           bmp.usReserved      = 0;
  1336.           bmp.usRecording     = BRA_BOTTOMUP;
  1337.           bmp.usRendering     = BRH_NOTHALFTONED;
  1338.           bmp.cSize1          = 0;
  1339.           bmp.cSize2          = 0;
  1340.           bmp.ulColorEncoding = BCE_RGB;
  1341.           bmp.ulIdentifier    = 0;
  1342.  
  1343.           pbmi->cbFix         = bmp.cbFix;
  1344.           pbmi->cx            = cxClient;
  1345.           pbmi->cy            = cyClient;
  1346.           pbmi->cPlanes       = alData[0];
  1347.           pbmi->cBitCount     = alData[1];
  1348.           pbmi->ulCompression = BCA_UNCOMP;
  1349.           pbmi->cbImage       = ((cxClient+31)/32)*4;
  1350.           pbmi->cbImage       = bmp.cbImage;
  1351.           pbmi->cxResolution  = 70;
  1352.           pbmi->cyResolution  = 70;
  1353.           pbmi->cclrUsed      = bmp.cclrUsed;
  1354.           pbmi->cclrImportant = 0;
  1355.           pbmi->usUnits       = BRU_METRIC;
  1356.           pbmi->usReserved    = 0;
  1357.           pbmi->usRecording   = BRA_BOTTOMUP;
  1358.           pbmi->usRendering   = BRH_NOTHALFTONED;
  1359.           pbmi->cSize1        = 0;
  1360.           pbmi->cSize2        = 0;
  1361.           pbmi->ulColorEncoding = BCE_RGB;
  1362.           pbmi->ulIdentifier  = 0;
  1363.           for (i=0; i<maxcolor1; i++) {
  1364.              pbmi->argbColor[i].bBlue  =  blTable[i] & 0x000000ff;
  1365.              pbmi->argbColor[i].bGreen = (blTable[i] & 0x0000ff00) >> 8;
  1366.              pbmi->argbColor[i].bRed   = (blTable[i] & 0x00ff0000) >> 16;
  1367.           }
  1368.  
  1369.           // now create a bitmap which is compatible with display
  1370.          hbm = GpiCreateBitmap(hpsMem, &bmp, FALSE, NULL, NULL);
  1371.  
  1372.           // associate the bitmap and the memory presentation space
  1373.          hbmOld = GpiSetBitmap(hpsMem, hbm);
  1374.          GpiSetBitmapBits(hpsMem, 0L, cyClient, pBitmap, pbmi);
  1375.          GpiDeleteBitmap(hbmOld);
  1376.  
  1377.  
  1378.          // turn thread2 loose
  1379.          semrslt = DosQueryMutexSem(sema4, &pidowner, &tidowner, &claimcount);
  1380.          if ((tidowner == 1) && (claimcount > 0))  // does thread #1 own it?
  1381.            semrslt = DosReleaseMutexSem(sema4);
  1382.  
  1383.          /* turn thread3 loose */
  1384.          semrslt = DosQueryMutexSem(semsleeper, &pidowner, &tidowner, &claimcount);
  1385.          if ((tidowner == 1) && (claimcount > 0))  /* does thread #1 own it? */
  1386.            semrslt = DosReleaseMutexSem(semsleeper);
  1387.  
  1388.          /* turn thread4 loose */
  1389.          semrslt = DosQueryMutexSem(semcolorer, &pidowner, &tidowner, &claimcount);
  1390.          if ((tidowner == 1) && (claimcount > 0))  /* does thread #1 own it? */
  1391.            semrslt = DosReleaseMutexSem(semcolorer);
  1392.  
  1393.           WinReleasePS(hps);
  1394.  
  1395.          break;
  1396.  
  1397.       case WM_CLOSE:
  1398.          /* Tell the main procedure to terminate the message loop.            */
  1399.  
  1400.          WinPostMsg( hwnd, WM_QUIT, NULL, NULL );
  1401.          DosFreeMem((PPVOID)&pbmi);
  1402.          GpiDestroyPS(hpsMem);
  1403.          DevCloseDC(hdcMem);
  1404.          GpiDeleteBitmap(hbm);
  1405.          break;
  1406.  
  1407.       case WM_PAINT:
  1408.          hps = WinBeginPaint( hwnd, NULLHANDLE, NULL );
  1409.          for (i=0; i<maxcolor1; i++) {
  1410.              pbmi->argbColor[i].bBlue  =  blTable[i] & 0x000000ff;
  1411.              pbmi->argbColor[i].bGreen = (blTable[i] & 0x0000ff00) >> 8;
  1412.              pbmi->argbColor[i].bRed   = (blTable[i] & 0x00ff0000) >> 16;
  1413.          }
  1414.  
  1415.          aptl[0].x = 0;
  1416.          aptl[0].y = 0;
  1417.          aptl[1].x = cxClient-1;
  1418.          aptl[1].y = cyClient-1;
  1419.          aptl[2].x = 0;
  1420.          aptl[2].y = 0;
  1421.          aptl[3].x = cxCold-1;
  1422.          aptl[3].y = cyCold-1;
  1423.  
  1424.          // set up the file rectangle
  1425.          aptflFile[0].x = 0;
  1426.          aptflFile[0].y = 0;
  1427.          aptflFile[1].x = cxClient-1;
  1428.          aptflFile[1].y = cyClient-1;
  1429.          aptflFile[2].x = 0;
  1430.          aptflFile[2].y = 0;
  1431.          aptflFile[3].x = cxfilebmp-1;
  1432.          aptflFile[3].y = cyfilebmp-1;
  1433.  
  1434.          GpiSetBitmapBits(hpsMem, 0L, cyClient, pBitmap, pbmi);
  1435.  
  1436.  
  1437.          if (colorit) {
  1438.              if (hpsfile == NULLHANDLE)
  1439.                  GpiBitBlt(hps, hpsMem, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  1440.              else {  // we are viewing a bitmap from a file
  1441.                 // blast from hpsfile (load bitmap from file)
  1442.                  GpiBitBlt(hps, hpsfile, 4L, aptflFile, ROP_SRCCOPY, BBO_IGNORE);
  1443.              }
  1444.          }
  1445.          else {
  1446.             WinQueryWindowRect(hwnd, &rectl);  // gonna draw orbits
  1447.             WinFillRect(hps, &rectl, CLR_BLACK);
  1448.          }
  1449.  
  1450.          // now draw the zoom box - if needed
  1451.          if (fCapture || fShowBox) {
  1452.             GpiSetMix(hps, FM_INVERT);
  1453.             GpiMove(hps, &ptlStart);
  1454.             GpiBox(hps, DRO_OUTLINE, &ptlEnd, 0L, 0L);
  1455.          }
  1456.  
  1457.          WinEndPaint( hps );
  1458.  
  1459.          break;
  1460.  
  1461.       case WM_COMMAND:
  1462.          // The user has chosen a menu item.  Process the selection.
  1463.          switch ( SHORT1FROMMP( mp1 ) )
  1464.          {
  1465.             case IDM_EXITPROG:
  1466.                // Post a close message.
  1467.                WinPostMsg( hwnd, WM_CLOSE, NULL, NULL );
  1468.                break;
  1469.  
  1470.             case IDM_RESUME:
  1471.                WinPostQueueMsg( hmqThread2, WM_USER_REPAINT, 0UL, 0UL );
  1472.                break;
  1473.  
  1474.             case IDM_MANDEL :
  1475.                      fractype = MANDEL;
  1476.                      SwitchCheck(IDM_MANDEL, &CurrentFractalChecked);
  1477.                      UpdateTitle(hwndFrame, szAppName, MANDELZ);
  1478.                      break;
  1479.             case IDM_LAMBDA:
  1480.                      fractype = LAMBDA;
  1481.                      SwitchCheck(IDM_LAMBDA, &CurrentFractalChecked);
  1482.                      UpdateTitle(hwndFrame, szAppName, LAMBDAZ);
  1483.                      break;
  1484.             case IDM_CMPLXNEWT:
  1485.                      fractype = CMPLXNEWT;
  1486.                      SwitchCheck(IDM_CMPLXNEWT, &CurrentFractalChecked);
  1487.                      UpdateTitle(hwndFrame, szAppName, CMPLXNEWTZ);
  1488.                      break;
  1489.             case IDM_JULIA1:
  1490.                      fractype = JULIA1;
  1491.                      SwitchCheck(IDM_JULIA1, &CurrentFractalChecked);
  1492.                      UpdateTitle(hwndFrame, szAppName, JULIAZ);
  1493.                      break;
  1494.             case IDM_CMPLXMAN:
  1495.                       fractype = COMPLEXMAND;
  1496.                       SwitchCheck(IDM_CMPLXMAN, &CurrentFractalChecked);
  1497.                       UpdateTitle(hwndFrame, szAppName, COMPLEXMANDZ);
  1498.                       break;
  1499.             case IDM_MAGNETJ1:
  1500.                       fractype = MAGNETJ1;
  1501.                       SwitchCheck(IDM_MAGNETJ1, &CurrentFractalChecked);
  1502.                       UpdateTitle(hwndFrame, szAppName, MAGNETJ1Z);
  1503.                       break;
  1504.             case IDM_TETRATION:
  1505.                       fractype = TETRATION;
  1506.                       SwitchCheck(IDM_TETRATION, &CurrentFractalChecked);
  1507.                       UpdateTitle(hwndFrame, szAppName, TETRATIONZ);
  1508.                       break;
  1509.             case IDM_SPIDER :
  1510.                       fractype = SPIDER;
  1511.                       SwitchCheck(IDM_SPIDER, &CurrentFractalChecked);
  1512.                       UpdateTitle(hwndFrame, szAppName, SPIDERZ);
  1513.                       break;
  1514.             case IDM_RESET :
  1515.                       if (hpsfile != NULLHANDLE)
  1516.                          GpiDestroyPS(hpsfile);  // make sure it's deceased
  1517.                       hpsfile = NULLHANDLE;
  1518.                       iy = 0;
  1519.                       xlv = -2.5;
  1520.                       xrv = 1.5;
  1521.                       ybv = -1.5;
  1522.                       ytv = 1.5;
  1523.                       dxv = xrv - xlv;
  1524.                       dyv = ytv - ybv;
  1525.                       showorbits = 0;
  1526.                       xperturb = 0.0;
  1527.                       yperturb = 0.0;
  1528.                       three_d = 0;
  1529.                       usepotential = 0;
  1530.                       spherical = FALSE;
  1531.                       fractype = MANDEL;   // initial default
  1532.                       SwitchCheck(IDM_MANDEL, &CurrentFractalChecked);
  1533.                       UpdateTitle(hwndFrame, szAppName, MANDELZ);
  1534.                       break;
  1535.  
  1536.             case IDM_SAVE :
  1537.                     if (SaveAsBitmap() )
  1538.                        DisplayMessage(hab, IDS_FAILCREATE );
  1539.                     break;
  1540.  
  1541.             case IDM_VIEW :
  1542.                     CheckMenu(IDM_VIEW, TRUE);
  1543.                     CheckMenu(IDM_UNVIEW, FALSE);
  1544.                     if (LoadFractalBitmap() ) {
  1545.                       DisplayMessage(hab, IDS_FAILOPEN);
  1546.                       break;
  1547.                     }
  1548.                     hdcMemfile = DevOpenDC(hab, OD_MEMORY, "*", 4,
  1549.                                           (PDEVOPENDATA) pszData, NULLHANDLE);
  1550.                     hpsfile = GpiCreatePS(hab, hdcMemfile, &sizlFilePage,
  1551.                                           PU_PELS | GPIT_MICRO | GPIA_ASSOC );
  1552.                     hbmfile = GpiCreateBitmap(hpsfile, (PBITMAPINFOHEADER2) pbmp2,
  1553.                                               0, NULL, NULL);
  1554.                     // associate the bitmap and the memory presentation space
  1555.                     GpiSetBitmap(hpsfile, hbmfile);
  1556.                     GpiSetBitmapBits(hpsfile,
  1557.                                      0L,            // scanstart
  1558.                                      pbmp2->cy,     // #of scans
  1559.                                      pBitsfile,     // the bitmap
  1560.                                      pbmp2);
  1561.                     break;
  1562.  
  1563.             case IDM_UNVIEW :
  1564.                     CheckMenu(IDM_VIEW, FALSE);
  1565.                     CheckMenu(IDM_UNVIEW, TRUE);
  1566.                     GpiDestroyPS(hpsfile);
  1567.                     DevCloseDC(hdcMemfile);
  1568.                     GpiDeleteBitmap(hbmfile);
  1569.                     hpsfile = NULLHANDLE;
  1570.                     DosFreeMem(pbmpfileheader2);  // allocated in LoadFractalBitmap
  1571.                     break;
  1572.  
  1573.             case IDM_ORBIT :
  1574.                     SwitchCheck(IDM_ORBIT, &CurrentImageOrbitsChecked);
  1575.                     showorbits = 1;
  1576.                     colorit = 0;
  1577.                     break;
  1578.             case IDM_IMAGE :
  1579.                     SwitchCheck(IDM_IMAGE, &CurrentImageOrbitsChecked);
  1580.                     showorbits = 0;
  1581.                     colorit = 1;
  1582.                     break;
  1583.             case IDM_FIXCOLORS :
  1584.                     SwitchCheck(IDM_FIXCOLORS, &CurrentFixChangeColorsChecked);
  1585.                     changecolors = 0;
  1586.                     break;
  1587.             case IDM_CHANGECOLORS :
  1588.                     SwitchCheck(IDM_CHANGECOLORS, &CurrentFixChangeColorsChecked);
  1589.                     changecolors = 1;
  1590.                     break;
  1591.  
  1592.             case IDM_DEFAULT :  // start of color maps
  1593.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1594.                     CheckComplementAgain = FALSE;
  1595.                     SwitchCheck(IDM_DEFAULT, &CurrentMapChecked);
  1596.                     LoadColors(".\\default.map", blTable, maxcolor1);
  1597.                     break;
  1598.             case IDM_ALTERN :
  1599.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1600.                     CheckComplementAgain = FALSE;
  1601.                     SwitchCheck(IDM_ALTERN, &CurrentMapChecked);
  1602.                     LoadColors(".\\altern.map", blTable, maxcolor1);
  1603.                     break;
  1604.             case IDM_BLUES :
  1605.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1606.                     CheckComplementAgain = FALSE;
  1607.                     SwitchCheck(IDM_BLUES, &CurrentMapChecked);
  1608.                     LoadColors(".\\blues.map", blTable, maxcolor1);
  1609.                     break;
  1610.             case IDM_CHROMA :
  1611.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1612.                     CheckComplementAgain = FALSE;
  1613.                     SwitchCheck(IDM_CHROMA, &CurrentMapChecked);
  1614.                     LoadColors(".\\chroma.map", blTable, maxcolor1);
  1615.                     break;
  1616.             case IDM_DARKGREY :
  1617.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1618.                     CheckComplementAgain = FALSE;
  1619.                     SwitchCheck(IDM_DARKGREY, &CurrentMapChecked);
  1620.                     LoadColors(".\\darkgrey.map", blTable, maxcolor1);
  1621.                     break;
  1622.             case IDM_FIRESTRM :
  1623.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1624.                     CheckComplementAgain = FALSE;
  1625.                     SwitchCheck(IDM_FIRESTRM, &CurrentMapChecked);
  1626.                     LoadColors(".\\firestrm.map", blTable, maxcolor1);
  1627.                     break;
  1628.             case IDM_GAMMA1 :
  1629.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1630.                     CheckComplementAgain = FALSE;
  1631.                     SwitchCheck(IDM_GAMMA1, &CurrentMapChecked);
  1632.                     LoadColors(".\\gamma1.map", blTable, maxcolor1);
  1633.                     break;
  1634.             case IDM_GAMMA2 :
  1635.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1636.                     CheckComplementAgain = FALSE;
  1637.                     SwitchCheck(IDM_GAMMA2,  &CurrentMapChecked);
  1638.                     LoadColors(".\\gamma2.map", blTable, maxcolor1);
  1639.                     break;
  1640.             case IDM_GREEN :
  1641.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1642.                     CheckComplementAgain = FALSE;
  1643.                     SwitchCheck(IDM_GREEN, &CurrentMapChecked);
  1644.                     LoadColors(".\\green.map", blTable, maxcolor1);
  1645.                     break;
  1646.             case IDM_GREY :
  1647.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1648.                     CheckComplementAgain = FALSE;
  1649.                     SwitchCheck(IDM_GREY, &CurrentMapChecked);
  1650.                     LoadColors(".\\grey.map", blTable, maxcolor1);
  1651.                     break;
  1652.             case IDM_LANDSCAP :
  1653.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1654.                     CheckComplementAgain = FALSE;
  1655.                     SwitchCheck(IDM_LANDSCAP, &CurrentMapChecked);
  1656.                     LoadColors(".\\landscap.map", blTable, maxcolor1);
  1657.                     break;
  1658.             case IDM_NEON :
  1659.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1660.                     CheckComplementAgain = FALSE;
  1661.                     SwitchCheck(IDM_NEON, &CurrentMapChecked);
  1662.                     LoadColors(".\\neon.map", blTable, maxcolor1);
  1663.                     break;
  1664.             case IDM_PAINTJET :
  1665.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1666.                     CheckComplementAgain = FALSE;
  1667.                     SwitchCheck(IDM_PAINTJET, &CurrentMapChecked);
  1668.                     LoadColors (".\\paintjet", blTable, maxcolor1);
  1669.                     break;
  1670.             case IDM_ROYAL :
  1671.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1672.                     CheckComplementAgain = FALSE;
  1673.                     SwitchCheck(IDM_ROYAL, &CurrentMapChecked);
  1674.                     LoadColors(".\\royal.map", blTable, maxcolor1);
  1675.                     break;
  1676.             case IDM_TOPO :
  1677.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1678.                     CheckComplementAgain = FALSE;
  1679.                     SwitchCheck(IDM_TOPO, &CurrentMapChecked);
  1680.                     LoadColors(".\\topo.map", blTable, maxcolor1);
  1681.                     break;
  1682.             case IDM_VOLCANO :
  1683.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1684.                     CheckComplementAgain = FALSE;
  1685.                     SwitchCheck(IDM_VOLCANO, &CurrentMapChecked);
  1686.                     LoadColors(".\\volcano.map", blTable, maxcolor1);
  1687.                     break;
  1688.             case IDM_RANDOM :
  1689.                     CheckMenu(IDM_COMPLEMENT, FALSE);
  1690.                     CheckComplementAgain = FALSE;
  1691.                     SwitchCheck(IDM_RANDOM, &CurrentMapChecked);
  1692.                     LoadColors(".\\random.map", blTable, maxcolor1);
  1693.                     break;
  1694.             case IDM_COMPLEMENT :
  1695.                     CheckComplementAgain ^= TRUE;
  1696.                     CheckMenu(IDM_COMPLEMENT, CheckComplementAgain);
  1697.                     for (i=1; i<maxcolor1; i++)
  1698.                       blTable[i] = (~blTable[i]) & 0xffffff;
  1699.                     break;
  1700.  
  1701.             case IDM_SETTINGS:
  1702.                 WinDlgBox(HWND_DESKTOP, hwnd, SettingsDlg, 0, DLG_SETTINGS, 0);
  1703.                 return 0;
  1704.  
  1705.             case IDM_HELPINSTRUCTIONS:
  1706.                /* Display the help dialog box.                                */
  1707.  
  1708.                WinMessageBox( HWND_DESKTOP,      /* desktop is the parent     */
  1709.                               hwnd,              /* owned by client window    */
  1710.                               INSTRUCTIONS,      /* pointer to message text   */
  1711.                               szAppName,         /* pointer to title text     */
  1712.                               1UL,               /* message box identifier    */
  1713.                               MB_OK | MB_INFORMATION | /* message box style   */
  1714.                               MB_APPLMODAL | MB_MOVEABLE );
  1715.  
  1716.                break;
  1717.  
  1718.             case IDM_HELPABOUT:
  1719.                /* Display the help dialog box.                                */
  1720.  
  1721.                WinDlgBox( HWND_DESKTOP,     /* make the desktop the parent    */
  1722.                           hwnd,             /* owned by client window         */
  1723.                           HelpDlgProc,      /* address of dialog procedure    */
  1724.                           0UL,              /* module handle                  */
  1725.                           IDD_HELP,         /* dialog identifier in resource  */
  1726.                           NULL );           /* initialization data            */
  1727.  
  1728.                break;
  1729.          }
  1730.          WinInvalidateRect(hwndClient, NULL, FALSE);
  1731.          break;
  1732.  
  1733.  
  1734.       case WM_BUTTON1DOWN:
  1735.          WinSetFocus( HWND_DESKTOP, hwnd );
  1736.          ptlStart.x = ptlEnd.x = MOUSEMSG(&msg)->x;
  1737.          ptlStart.y = ptlEnd.y = MOUSEMSG(&msg)->y;
  1738.  
  1739.          DrawBoxOutline(hwnd, &ptlStart, &ptlEnd);
  1740.  
  1741.          WinSetCapture(HWND_DESKTOP, hwnd);
  1742.          fCapture = TRUE;
  1743.  
  1744.          return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  1745.  
  1746.       case WM_BUTTON1DBLCLK:
  1747.           // The user has double clicked mouse button 1 which means
  1748.           // clear to black and redraw
  1749.          iy = 0;
  1750.          memset(pBitmap, 0, databytes);
  1751.          WinInvalidateRect(hwnd, NULL, FALSE);
  1752.          break;
  1753.  
  1754.       case WM_BUTTON2DOWN:  // switch to Julia
  1755.          ix0 = MOUSEMSG(&msg)->x;
  1756.          iy0 = MOUSEMSG(&msg)->y;
  1757.          cy0 = ytv + (double)(iy0 - maxyp) * dyv/rmaxyp;
  1758.          cx0 = dxv * (double) ix0/rmaxxp + xlv;
  1759.          xperturb = cx0;         // these two mostly for dialog box field
  1760.          yperturb = cy0;
  1761.          c0 = complex(cx0, cy0);
  1762.          fractype = JULIACLICK;
  1763.          UpdateTitle(hwndFrame, szAppName, JULIAZ);
  1764.          SwitchCheck(IDM_JULIA1, &CurrentFractalChecked);
  1765.          xlv = -2.0;    // now start it big again
  1766.          xrv = 2.0;
  1767.          ybv = -1.5;
  1768.          ytv = 1.5;
  1769.          dxv = xrv - xlv;
  1770.          dyv = ytv - ybv;
  1771.          return (MRESULT) TRUE;
  1772.  
  1773.       case WM_BUTTON1UP:
  1774.          if (fCapture) {
  1775.              ptlBoxStart = ptlStart;
  1776.              ptlBoxEnd.x = MOUSEMSG(&msg)->x;
  1777.              ptlBoxEnd.y = MOUSEMSG(&msg)->y;
  1778.              WinSetCapture(HWND_DESKTOP, NULLHANDLE);   // off
  1779.              fCapture = FALSE;
  1780.              fShowBox = FALSE;
  1781.              ixl = ptlBoxStart.x;
  1782.              ixr = ptlBoxEnd.x;
  1783.              iyt = ptlBoxStart.y;
  1784.              iyb = ptlBoxEnd.y;
  1785.              if (ixl > ixr) {
  1786.                temp = ixl;
  1787.                ixl = ixr;
  1788.                ixr = temp;
  1789.              }
  1790.              if (iyb > iyt) {
  1791.                temp = iyb;
  1792.                iyb = iyt;
  1793.                iyt = temp;
  1794.              }
  1795.              // check for small box - user reject or clear box
  1796.              if (((ixl - ixr) < 8) && ((iyt - iyb) < 8)) {
  1797.                   fShowBox = FALSE;
  1798.                   fCapture = FALSE;
  1799.                   break;
  1800.              }
  1801.              dxv = xrv - xlv;
  1802.              dyv = ytv - ybv;
  1803.              rmaxxp = (double) (cxClient-1);
  1804.              rmaxyp = (double) (cyClient-1);
  1805.  
  1806.              xrv = dxv * (double) ixr / rmaxxp + xlv;
  1807.              xlv = dxv * (double) ixl / rmaxxp + xlv;
  1808.  
  1809.              ybv = ytv + ((double)iyb - rmaxyp)/rmaxyp * dyv;
  1810.              ytv = ytv + ((double)iyt - rmaxyp)/rmaxyp * dyv;
  1811.              dxv = xrv - xlv;
  1812.              dyv = ytv - ybv;
  1813.              WinInvalidateRect(hwnd, NULL, FALSE);
  1814.          }
  1815.          break;
  1816.  
  1817.       case WM_MOUSEMOVE:
  1818.          if (fCapture) {
  1819.              DrawBoxOutline(hwnd, &ptlStart, &ptlEnd);
  1820.              ptlEnd.x = MOUSEMSG(&msg)->x;
  1821.              ptlEnd.y = MOUSEMSG(&msg)->y;
  1822.              DrawBoxOutline(hwnd, &ptlStart, &ptlEnd);
  1823.          }
  1824.          return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  1825.  
  1826.       case WM_DESTROY:
  1827.          /* The client window is being destroyed so tell the second thread to */
  1828.          /* stop running.                                                     */
  1829.  
  1830.          WinPostQueueMsg( hmqThread2, WM_USER_END_THREAD, 0UL, 0UL );
  1831.  
  1832.          /* Wait for the drawing thread to terminate before returning.        */
  1833.  
  1834.          DosWaitThread( &tidDrawing, DCWW_WAIT );
  1835.  
  1836.          break;
  1837.        default:
  1838.          /* For all other messages, let the default window procedure          */
  1839.          /* process them.                                                     */
  1840.  
  1841.          return ( WinDefWindowProc( hwnd, msg, mp1, mp2 ) );
  1842.  
  1843.    }
  1844.    return 0;
  1845. }
  1846. /*+--------------------------------------------------------------------------+*/
  1847. /*| BasicSettingsDlg -                                                       |*/
  1848. /*+--------------------------------------------------------------------------+*/
  1849.  
  1850. static MRESULT EXPENTRY BasicSettingsDlg ( HWND hwndSettings, ULONG msg, MPARAM mp1, MPARAM mp2)
  1851. {
  1852. static HWND hwndlbox;
  1853. char
  1854.      xpstr[20],
  1855.      ypstr[20],  // perturbation strings
  1856.      xlstr[20],
  1857.      xrstr[20],
  1858.      ybstr[20],
  1859.      ytstr[20],  // input/output params for four fields
  1860.      iterstr[20],
  1861.      bailoutstr[20],
  1862.      examplestr[30],
  1863.      formulastr[40];
  1864.  
  1865.    switch(msg)
  1866.    {
  1867.        case WM_INITDLG:
  1868.           hwndlbox = HWNDFROMMP(mp1);
  1869.           sprintf(xlstr, "%lf", xlv);
  1870.           sprintf(xrstr, "%lf", xrv);
  1871.           sprintf(ybstr, "%lf", ybv);
  1872.           sprintf(ytstr, "%lf", ytv);
  1873.           sprintf(iterstr, "%ld", maxiter);
  1874.           sprintf(bailoutstr, "%3.1lf", bailout);
  1875.           sprintf(xpstr, "%lf", xperturb);
  1876.           sprintf(ypstr, "%lf", yperturb);
  1877.  
  1878.           switch (fractype) {
  1879.             case MANDEL:
  1880.                strcpy(fractnamestr, MANDELZ);
  1881.                strcpy(formulastr, "z = z^2 + c");
  1882.                strcpy(examplestr, "(0,0)");
  1883.                break;
  1884.             case LAMBDA:
  1885.                strcpy(fractnamestr, LAMBDAZ);
  1886.                strcpy(formulastr, "z = c*z*(1-z)");
  1887.                strcpy(examplestr, "(0.85,0.6)");
  1888.                break;
  1889.             case CMPLXNEWT:
  1890.                strcpy(fractnamestr, CMPLXNEWTZ);
  1891.                strcpy(formulastr, "z = ((n-1)z^n+r)/(n*z^(n-1))");
  1892.                strcpy(examplestr, "(3,0)");
  1893.                break;
  1894.             case JULIA1:
  1895.                strcpy(fractnamestr, JULIAZ);
  1896.                strcpy(formulastr, "z = z*z + c");
  1897.                strcpy(examplestr, "(var,var)");
  1898.                break;
  1899.             case COMPLEXMAND:
  1900.                strcpy(fractnamestr, COMPLEXMANDZ);
  1901.                strcpy(formulastr, "z = z*z*c^(p-1)+c");
  1902.                strcpy(examplestr, "(1,0)");
  1903.                break;
  1904.             case JULIACLICK:  // switch to Julia
  1905.                strcpy(fractnamestr, JULIAZ);
  1906.                strcpy(formulastr, "z = z^2 + c");
  1907.                strcpy(examplestr, "(clk_x,clk_y)");
  1908.                break;
  1909.             case MAGNETJ1:
  1910.                strcpy(fractnamestr, MAGNETJ1Z);
  1911.                strcpy(formulastr, "(see ref. 1)");
  1912.                strcpy(examplestr, "(0.3,0.6)");
  1913.                break;
  1914.             case TETRATION:
  1915.                strcpy(fractnamestr, TETRATIONZ);
  1916.                strcpy(formulastr, "z = c^z");
  1917.                strcpy(examplestr, "(0,0) see ref");
  1918.                break;
  1919.             case SPIDER :
  1920.                strcpy(fractnamestr, SPIDERZ);
  1921.                strcpy(formulastr, "z=z^2+c;c=c/2+z");
  1922.                strcpy(examplestr, "(0,0)");
  1923.             default:
  1924.               break;
  1925.           }
  1926.           WinSetDlgItemText(hwndSettings, DLG_FRACTNAME, fractnamestr);
  1927.           WinSetDlgItemText(hwndSettings, DLG_FORMULA, formulastr);
  1928.           WinSetDlgItemText(hwndSettings, DLG_EXAMPLEPERTS, examplestr);
  1929.  
  1930.           WinSetDlgItemText(hwndSettings, DLG_XLEFT, xlstr);
  1931.           WinSetDlgItemText(hwndSettings, DLG_XRIGHT, xrstr);
  1932.           WinSetDlgItemText(hwndSettings, DLG_YBOTTOM, ybstr);
  1933.           WinSetDlgItemText(hwndSettings, DLG_YTOP, ytstr);
  1934.           WinSetDlgItemText(hwndSettings, DLG_REALNO, xpstr);
  1935.           WinSetDlgItemText(hwndSettings, DLG_IMAGNO, ypstr);
  1936.           WinSetDlgItemText(hwndSettings, DLG_MAXITER, iterstr);
  1937.           WinSetDlgItemText(hwndSettings, DLG_BAILOUT, bailoutstr);
  1938.           return (MRESULT)TRUE;
  1939.  
  1940.        case WM_COMMAND:
  1941.            switch( SHORT1FROMMP( mp1 ) ) // Extract the command value
  1942.            {
  1943.               case DID_OK:
  1944.                  WinQueryDlgItemText(hwndSettings, DLG_XLEFT, 20, xlstr);
  1945.                  WinQueryDlgItemText(hwndSettings, DLG_XRIGHT, 20, xrstr);
  1946.                  WinQueryDlgItemText(hwndSettings, DLG_YBOTTOM, 20, ybstr);
  1947.                  WinQueryDlgItemText(hwndSettings, DLG_YTOP, 20, ytstr);
  1948.                  xlv = atof(xlstr);
  1949.                  xrv = atof(xrstr);
  1950.                  ybv = atof(ybstr);
  1951.                  ytv = atof(ytstr);
  1952.                  dxv = xrv - xlv;
  1953.                  dyv = ytv - ybv;
  1954.                  WinQueryDlgItemText(hwndSettings, DLG_REALNO, 20, xpstr);
  1955.                  WinQueryDlgItemText(hwndSettings, DLG_IMAGNO, 20, ypstr);
  1956.                  xperturb = atof(xpstr);
  1957.                  yperturb = atof(ypstr);
  1958.                  WinQueryDlgItemText(hwndSettings, DLG_MAXITER, 20, iterstr);
  1959.                  WinQueryDlgItemText(hwndSettings, DLG_BAILOUT, 20, bailoutstr);
  1960.                  maxiter = atoi(iterstr);
  1961.                  bailout = atof(bailoutstr);
  1962.                  return 0;
  1963.               case DID_CANCEL:
  1964.                  return 0;
  1965.            }
  1966.            break;
  1967.  
  1968.        default:
  1969.            break;
  1970.    }
  1971.    mp2;  // not referenced
  1972.    return (MRESULT) 0;
  1973. }
  1974.  
  1975.  
  1976. LONG ReadSliderPosition(HWND hwnd, int Which1)
  1977. {
  1978.     return (LONG) WinSendDlgItemMsg(
  1979.                                      hwnd,
  1980.                                      Which1,
  1981.                                      SLM_QUERYSLIDERINFO,
  1982.                                      MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE),
  1983.                                      NULL);
  1984. }
  1985.  
  1986. BOOL InitializeSlider(HWND hwnd, int Which1)
  1987. {
  1988.     USHORT index;
  1989.     LONG degrees;
  1990.     CHAR acBuffer[4];
  1991.     CHAR *cData;
  1992.  
  1993.     cData = ltoa(0, acBuffer, 10);
  1994.     WinSetDlgItemText(hwnd, Which1, cData);
  1995.     /*--------------------------------------
  1996.     if (!WinSendDlgItemMsg(hwnd,                this is very dense. use if desired
  1997.                            Which1,
  1998.                            SLM_SETTICKSIZE,
  1999.                            MPFROM2SHORT(SMA_SETALLTICKS, 3),
  2000.                            NULL) )
  2001.               return FALSE;
  2002.     ------------------------------------------------*/
  2003.     for (index = 0; index <= 180; index+=10){
  2004.         degrees = -90 + index;
  2005.         cData = ltoa(degrees, acBuffer, 10);
  2006.         if (!WinSendDlgItemMsg(hwnd,
  2007.                                Which1,
  2008.                                SLM_SETSCALETEXT,
  2009.                                MPFROMSHORT(index),
  2010.                                MPFROMP(cData) ) )
  2011.                   return FALSE;
  2012.         if (!WinSendDlgItemMsg(hwnd,
  2013.                                Which1,
  2014.                                SLM_SETTICKSIZE,
  2015.                                MPFROM2SHORT(index, 7),
  2016.                                NULL) )
  2017.                   return FALSE;
  2018.     }
  2019.     for (index = 5; index <= 175; index+=10){   // now set some smaller ticks
  2020.          if (!WinSendDlgItemMsg(hwnd,
  2021.                                Which1,
  2022.                                SLM_SETTICKSIZE,
  2023.                                MPFROM2SHORT(index, 4),
  2024.                                NULL) )
  2025.                   return FALSE;
  2026.     }
  2027.  
  2028.      switch(Which1) {
  2029.         case DLGA_ALPHA :
  2030.            index = ((SHORT) alpha + 90);
  2031.            break;
  2032.         case DLGA_BETA :
  2033.            index = ((SHORT) beta + 90);
  2034.            break;
  2035.         case DLGA_PHI :
  2036.            index = ((SHORT) phi + 90);
  2037.            break;
  2038.         default :
  2039.            break;
  2040.      }
  2041.      WinSendDlgItemMsg(         // now move the slider to alpha, beta, phi
  2042.                  hwnd,
  2043.                  Which1,
  2044.                  SLM_SETSLIDERINFO,
  2045.                  MPFROM2SHORT(SMA_SLIDERARMPOSITION, SMA_INCREMENTVALUE),
  2046.                  MPFROMSHORT(index));
  2047.  
  2048.     return TRUE;
  2049. }
  2050.  
  2051. static MRESULT EXPENTRY AdvancedSettingsDlg ( HWND hwndSettings, ULONG msg, MPARAM mp1, MPARAM mp2)
  2052. {
  2053. static HWND hwndlbox;
  2054. char
  2055.      maxhtstr[20],
  2056.      insidecolorstr[20],
  2057.      bailoutstr[20];
  2058.  
  2059. LONG
  2060.      ulalpha,
  2061.      ulbeta,
  2062.      ulphi;
  2063.  
  2064.    switch(msg)
  2065.    {
  2066.        case WM_INITDLG:
  2067.           hwndlbox = HWNDFROMMP(mp1);
  2068.           sprintf(maxhtstr, "%4.1lf", maxheight);
  2069.           sprintf(insidecolorstr, "%3ld", insidecolor);
  2070.           sprintf(bailoutstr, "%6.1lf", bailout);
  2071.           WinSetDlgItemText(hwndSettings, DLGA_MAXHT, maxhtstr);
  2072.           WinSetDlgItemText(hwndSettings, DLGA_INSIDECOLOR, insidecolorstr);
  2073.  
  2074.           WinCheckButton(hwndSettings, DLGA_THREED, three_d);
  2075.           WinCheckButton(hwndSettings, DLGA_USEPOTENTIAL, usepotential);
  2076.  
  2077.           if (autoscale) {
  2078.              WinCheckButton(hwndSettings, DLG_AUTOYES, TRUE);
  2079.              WinCheckButton(hwndSettings, DLG_AUTONO, FALSE);
  2080.           }
  2081.           else {
  2082.              WinCheckButton(hwndSettings, DLG_AUTOYES, FALSE);
  2083.              WinCheckButton(hwndSettings, DLG_AUTONO, TRUE);
  2084.           }
  2085.  
  2086.           InitializeSlider(hwndSettings, DLGA_ALPHA);
  2087.           InitializeSlider(hwndSettings, DLGA_BETA);
  2088.           InitializeSlider(hwndSettings, DLGA_PHI);
  2089.  
  2090.           return (MRESULT)0;
  2091.       case WM_COMMAND:
  2092.            switch( SHORT1FROMMP( mp1 ) ) // Extract the command value
  2093.            {
  2094.               case DID_OK:
  2095.                  ulalpha = ReadSliderPosition(hwndSettings, DLGA_ALPHA);
  2096.                  alpha = (double) (ulalpha - 90);
  2097.                  ulbeta = ReadSliderPosition(hwndSettings, DLGA_BETA);
  2098.                  beta = (double) (ulbeta - 90);
  2099.                  ulphi = ReadSliderPosition(hwndSettings, DLGA_PHI);
  2100.                  phi = (double) (ulphi - 90);
  2101.                  three_d = WinQueryButtonCheckstate(hwndSettings, DLGA_THREED);
  2102.                  usepotential = WinQueryButtonCheckstate(hwndSettings, DLGA_USEPOTENTIAL);
  2103.                  autoscale = WinQueryButtonCheckstate(hwndSettings, DLG_AUTOYES);
  2104.                  WinQueryDlgItemText(hwndSettings, DLGA_MAXHT, 20, maxhtstr);
  2105.                  WinQueryDlgItemText(hwndSettings, DLGA_INSIDECOLOR, 20, insidecolorstr);
  2106.                  maxheight = atof(maxhtstr);
  2107.                  insidecolor = atoi(insidecolorstr);
  2108.                  return 0;
  2109.               case DID_CANCEL:
  2110.                  return 0;
  2111.            }
  2112.            break;
  2113.  
  2114.        default:
  2115.            break;
  2116.    }
  2117.    mp2; // not referenced
  2118.    return (MRESULT) 0;
  2119. }
  2120.  
  2121. static MRESULT EXPENTRY SpecialSettingsDlg(HWND hwndSettings, ULONG msg, MPARAM mp1, MPARAM mp2)
  2122. {
  2123. static HWND hwndlbox;
  2124. char
  2125.     radiusstr[20];
  2126.  
  2127.     switch(msg)
  2128.    {
  2129.        case WM_INITDLG :
  2130.           hwndlbox = HWNDFROMMP(mp1);
  2131.  
  2132.           if (sphere_covers_180) {
  2133.              WinCheckButton(hwndSettings, DLG_360, FALSE);
  2134.              WinCheckButton(hwndSettings, DLG_180, TRUE);
  2135.           }
  2136.           else {
  2137.              WinCheckButton(hwndSettings, DLG_180, FALSE);
  2138.              WinCheckButton(hwndSettings, DLG_360, TRUE);
  2139.           }
  2140.           sprintf(radiusstr, "%6.3lg", sphererad);
  2141.           WinSetDlgItemText(hwndSettings, DLG_SPHERERAD, radiusstr);
  2142.  
  2143.           WinCheckButton(hwndSettings, DLG_SPHERICAL, spherical);
  2144.  
  2145.           return (MRESULT) 0;
  2146.        case WM_COMMAND :
  2147.           switch(SHORT1FROMMP(mp1))
  2148.           {
  2149.               case DID_OK:
  2150.                   WinQueryDlgItemText(hwndSettings, DLG_SPHERERAD, 20, radiusstr);
  2151.                   sphererad = atof(radiusstr);
  2152.                   sphere_covers_180 = WinQueryButtonCheckstate(hwndSettings, DLG_180);
  2153.                   spherical = WinQueryButtonCheckstate(hwndSettings, DLG_SPHERICAL);
  2154.                   return 0;
  2155.               case DID_CANCEL :
  2156.                   return 0;
  2157.           }
  2158.           break;
  2159.  
  2160.        default :
  2161.           break;
  2162.    }
  2163.    mp2;   // not referenced
  2164.    return (MRESULT) 0;
  2165. }
  2166.  
  2167. /*+--------------------------------------------------------------------------+*/
  2168. /*|  SettingsDlg - Main Settings dialog procedure                            |*/
  2169. /*+--------------------------------------------------------------------------+*/
  2170.  
  2171. static MRESULT EXPENTRY SettingsDlg(HWND hwndSettings, ULONG msg, MPARAM mp1, MPARAM mp2)
  2172. {
  2173. int
  2174.      corner;   //corners of zoom box. there are 8 in 3-d space
  2175. double
  2176.      xpc,
  2177.      ypc,
  2178.      zpc,
  2179.      znc,
  2180.      zxc;  // stuff to rotate the zoom box if 3-D
  2181.  
  2182.    switch(msg)
  2183.  
  2184.    {
  2185.        case WM_INITDLG:
  2186.           BasicSettingsDlg(hwndSettings, msg, mp1, mp2);
  2187.           AdvancedSettingsDlg(hwndSettings, msg, mp1, mp2);
  2188.           SpecialSettingsDlg(hwndSettings, msg, mp1, mp2);
  2189.           break;
  2190.  
  2191.        case WM_COMMAND:
  2192.            switch( SHORT1FROMMP( mp1 ) ) // Extract the command value
  2193.            {
  2194.               case DID_OK:
  2195.                  BasicSettingsDlg(hwndSettings, msg, mp1, mp2);
  2196.                  AdvancedSettingsDlg(hwndSettings, msg, mp1, mp2);
  2197.                  SpecialSettingsDlg(hwndSettings, msg, mp1, mp2);
  2198.                  if (three_d) { // rotate the zoom box
  2199.                 sa = sin(alpha*rpd);
  2200.                 ca = cos(alpha*rpd);
  2201.                 sb = sin(beta*rpd);
  2202.                 cb = cos(beta*rpd);
  2203.                     sp = sin(phi*rpd);
  2204.                     cp = cos(phi*rpd);
  2205.                     if (!spherical)  {
  2206.                         xlp = 1.0e7;
  2207.                         xrp = -xlp;
  2208.                         ybp = xlp;
  2209.                         ytp = xrp;
  2210.                         znc = 0.0;                    // min y
  2211.                         if (usepotential) {
  2212.                            //zxc = potential/maxheight; // Oh boy, need to estimate this
  2213.                            zxc = 2.0*bailout/maxheight;
  2214.                         }
  2215.                         else
  2216.                            zxc = (double) maxcolor1/maxheight;
  2217.                         zbp = xlp;
  2218.                         ztp = -zbp;
  2219.                         for (corner=1; corner<=8; corner++) {
  2220.                            switch (corner)   // go through 8 corners of 3-d zoom box
  2221.                            {
  2222.                               case 1:
  2223.                                  rotpoint(xlv, ybv, znc, &xpc, &ypc, &zpc);
  2224.                                  break;
  2225.                               case 2:
  2226.                                  rotpoint(xlv, ybv, zxc, &xpc, &ypc, &zpc);
  2227.                                  break;
  2228.                               case 3:
  2229.                                  rotpoint(xrv, ybv, zxc, &xpc, &ypc, &zpc);
  2230.                                  break;
  2231.                               case 4:
  2232.                                  rotpoint(xrv, ybv, znc, &xpc, &ypc, &zpc);
  2233.                                  break;
  2234.                               case 5:
  2235.                                  rotpoint(xlv, ytv, znc, &xpc, &ypc, &zpc);
  2236.                                  break;
  2237.                               case 6:
  2238.                                  rotpoint(xlv, ytv, zxc, &xpc, &ypc, &zpc);
  2239.                                  break;
  2240.                               case 7:
  2241.                                  rotpoint(xrv, ytv, zxc, &xpc, &ypc, &zpc);
  2242.                                  break;
  2243.                               case 8:
  2244.                                  rotpoint(xrv, ytv, znc, &xpc, &ypc, &zpc);
  2245.                               default :
  2246.                                  break;
  2247.                            } // end switch
  2248.                            xlp = min(xlp, xpc);
  2249.                            xrp = max(xrp, xpc);
  2250.                            ybp = min(ybp, ypc);
  2251.                            ytp = max(ytp, ypc);
  2252.                            zbp = min(zbp, zpc);
  2253.                            ztp = max(ztp, zpc);
  2254.                         } // end for
  2255.                         dxvp = xrp - xlp;  // we now have the top, bottom, left, right pts
  2256.                         dyvp = ytp - ybp;  // of the rotated zoom box. Get lengths
  2257.                         dzvp = ztp - zbp;
  2258.                         //iy = 0;            // need a re-draw or ray-trace won't work
  2259.                         //memset(pBitmap, 0, databytes);
  2260.                     } // end (!spherical)
  2261.                     else // it is spherical
  2262.                     {
  2263.                         dxv = xrv - xlv;
  2264.                         sphererad = dxv/(2.0*pi);   // dxv is the circumference
  2265.                         if (sphere_covers_180)
  2266.                           sphererad *= 2.0;
  2267.                         ybps = -1.3*sphererad; // arbitrarily add 30 percent margin
  2268.                         ytps = 1.3*sphererad;
  2269.                         zbps = ybps;
  2270.                         ztps = ytps;
  2271.                         dyvps = ytps - ybps;
  2272.                         dzvps = ztps - zbps;
  2273.                         //  now make the sphere round
  2274.                         dxvps = dyvps * rmaxxp/rmaxyp;
  2275.                         xrps = dxvps/2.0;
  2276.                         xlps = -xrps;
  2277.                         //iy = 0;            // re-draw
  2278.                         //memset(pBitmap, 0, databytes);  don't think I like this
  2279.                     } // end else (spherical)
  2280.                  } // end if 3-d
  2281.                  WinDismissDlg(hwndSettings, TRUE);
  2282.                  return 0;
  2283.               case DID_CANCEL:
  2284.                  WinDismissDlg(hwndSettings, TRUE);
  2285.                  return 0;
  2286.               default :
  2287.                  break;
  2288.            }
  2289.  
  2290.        default:
  2291.            return WinDefDlgProc(hwndSettings, msg, mp1, mp2);
  2292.    }
  2293.    return (MRESULT) 0;
  2294. }
  2295.  
  2296.  
  2297. /*+--------------------------------------------------------------------------+*/
  2298. /*| HelpDlgProc - Help Dialog Procedure                                      |*/
  2299. /*+--------------------------------------------------------------------------+*/
  2300.  
  2301. static MRESULT EXPENTRY HelpDlgProc( HWND hwndDlg, ULONG msg, MPARAM mp1, MPARAM mp2 )
  2302. {
  2303.    switch( msg )
  2304.    {
  2305.       case WM_COMMAND:
  2306.          switch( SHORT1FROMMP( mp1 ) )      /* Extract the command value      */
  2307.          {
  2308.             case DID_OK:                    /* The Enter pushbutton or key    */
  2309.                WinDismissDlg( hwndDlg, TRUE );
  2310.                break;
  2311.  
  2312.             default:
  2313.                break;
  2314.          }
  2315.          break;
  2316.  
  2317.       default:
  2318.          return WinDefDlgProc( hwndDlg, msg, mp1, mp2 );
  2319.    }
  2320.    return NULL;
  2321. }
  2322.  
  2323.  
  2324. /*+--------------------------------------------------------------------------+*/
  2325. /*| DisplayMessage - display an error message in a message box.              |*/
  2326. /*+--------------------------------------------------------------------------+*/
  2327.  
  2328. static void DisplayMessage( HAB hab, ULONG ulStringNum )
  2329. {
  2330.    char szTemp[ STRING_LENGTH ];
  2331.  
  2332.    WinLoadString( hab, 0UL, ulStringNum, STRING_LENGTH, szTemp );
  2333.  
  2334.    WinAlarm( HWND_DESKTOP,                  /* desktop window handle          */
  2335.              WA_ERROR );                    /* type of alarm                  */
  2336.  
  2337.    WinMessageBox( HWND_DESKTOP,             /* parent window handle           */
  2338.                   HWND_DESKTOP,             /* owner window handle            */
  2339.                   szTemp,                   /* pointer to message text        */
  2340.                   szAppName,                /* pointer to title text          */
  2341.                   MSG_BOX_ID,               /* message box identifier         */
  2342.                   MB_OK | MB_ERROR |        /* message box style              */
  2343.                   MB_SYSTEMMODAL );
  2344.  
  2345.    return;
  2346. }
  2347.  
  2348.