home *** CD-ROM | disk | FTP | other *** search
/ Windows Graphics Programming / Feng_Yuan_Win32_GDI_DirectX.iso / Samples / Chapt_07 / Mandelbrot / Mandelbrot.cpp next >
Encoding:
C/C++ Source or Header  |  2000-05-20  |  10.9 KB  |  485 lines

  1. //-----------------------------------------------------------------------------------//
  2. //              Windows Graphics Programming: Win32 GDI and DirectDraw               //
  3. //                             ISBN  0-13-086985-6                                   //
  4. //                                                                                   //
  5. //  Written            by  Yuan, Feng                             www.fengyuan.com   //
  6. //  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
  7. //  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
  8. //                                                                                   //
  9. //  FileName   : mandelbrot.cpp                                                         //
  10. //  Description: Mandelbrot Set demo, Chapter 7                                      //
  11. //  Version    : 1.00.000, May 31, 2000                                              //
  12. //-----------------------------------------------------------------------------------//
  13.  
  14. #define STRICT
  15. #define WIN32_LEAN_AND_MEAN
  16.  
  17. #include <windows.h>
  18. #include <assert.h>
  19. #include <tchar.h>
  20. #include <stdio.h>
  21. #include <math.h>
  22.  
  23. #include "..\..\include\win.h"
  24. #include "..\..\include\Status.h"
  25. #include "..\..\include\Canvas.h"
  26. #include "..\..\include\ScrollCanvas.h"
  27. #include "..\..\include\FrameWnd.h"
  28. #include "..\..\include\GDIObject.h"
  29. #include "..\..\include\color.h"
  30.  
  31. #include "resource.h"
  32.  
  33. class KMyCanvas : public KScrollCanvas
  34. {
  35.     typedef enum { 
  36.                     MAX_LIMIT  = 16384,
  37.                     MAX_HEIGHT = 16384,
  38.     };
  39.     
  40.     virtual void    OnZoom(int x, int y, int mul, int div);
  41.     virtual BOOL    OnCommand(WPARAM wParam, LPARAM lParam);
  42.     virtual void    OnMouseMove(WPARAM wParam, LPARAM lParam);
  43.     virtual void    OnDraw(HDC hDC, const RECT * rcPaint);
  44.     virtual    void    OnTimer(WPARAM wParam, LPARAM lParam);
  45.  
  46.     virtual void OnCreate(void)
  47.     {
  48.         m_hTimer = ::SetTimer(m_hWnd, 111, 100, NULL);
  49.     }
  50.  
  51.     virtual void OnDestroy(void)
  52.     {
  53.         KillTimer(m_hWnd, m_hTimer);
  54.     }
  55.  
  56.  
  57.     int MandelCount(HDC hDC, int xi, int yi, int limit);
  58.  
  59.     double m_x, m_y, m_unit;
  60.     int    m_hTimer;
  61.     int    m_limit, m_lastlimit;
  62.     int    m_lastwidth, m_lastheight;
  63.     int    m_lastx0, m_lasty0;
  64.  
  65.     short * Buffer[MAX_HEIGHT];
  66.  
  67.     COLORREF Out[MAX_LIMIT];
  68.     COLORREF In [MAX_LIMIT];
  69.  
  70.     void SetLimit(int limit, BOOL bRedraw);
  71.     void ClearBuffer(int width, int height, int x, int y);
  72.  
  73. public:
  74.  
  75.     KMyCanvas()
  76.     {
  77.         m_x             = (double) - 2.1;
  78.         m_y             = (double) - 1.375;
  79.         m_unit         = (double) 1.0 / 256;
  80.         m_lastwidth  = 0;
  81.         m_lastheight = 0;
  82.                 
  83.         memset(Buffer, 0, sizeof(Buffer));
  84.         SetSize((int) (3 * 256), (int) (2.75 * 256), 24, 24);
  85.         SetLimit(32, FALSE);
  86.     }
  87.  
  88.     
  89.     ~KMyCanvas()
  90.     {
  91.         ClearBuffer(0, 0, 0, 0);
  92.     }
  93.  
  94. };
  95.  
  96.  
  97. void KMyCanvas::ClearBuffer(int width, int height, int x0, int y0)
  98. {
  99.     if ( (width!=m_lastwidth) || (height!=m_lastheight) )    
  100.     {
  101.         for (int i=0; i<sizeof(Buffer)/sizeof(Buffer[0]); i++)
  102.             if ( Buffer[i] )
  103.             {
  104.                 delete [] Buffer[i];
  105.  
  106.                 Buffer[i] = NULL;
  107.             }
  108.  
  109.         for (i=0; i<height; i++)
  110.         {
  111.             Buffer[i] = new short[width];
  112.  
  113.             memset(Buffer[i], 0, width * sizeof(short));
  114.         }
  115.  
  116.         m_lastwidth  = width;
  117.         m_lastheight = height;
  118.         m_lastx0     = x0;
  119.         m_lasty0     = y0;
  120.     }
  121.  
  122.     if ( y0 > m_lasty0 )    // move up
  123.     {
  124.         int n = y0 - m_lasty0;
  125.  
  126.         for (int y=0; y<height - n; y++)
  127.             memcpy(Buffer[y], Buffer[y+n], width * sizeof(short));
  128.  
  129.         for (; y<height; y++)
  130.             memset(Buffer[y], 0, width * sizeof(short));
  131.     } 
  132.     else if ( y0 < m_lasty0 )
  133.     {
  134.         int n = m_lasty0 - y0;
  135.  
  136.         for (int y=height-1; y>n; y--)
  137.             memcpy(Buffer[y], Buffer[y-n], width * sizeof(short));
  138.  
  139.         for (; y>=0; y--)
  140.             memset(Buffer[y], 0, width * sizeof(short));
  141.     }
  142.  
  143.     for (int y=0; y<height; y++)
  144.         if ( x0 > m_lastx0 )    // left
  145.         {
  146.             int n = x0 - m_lastx0;
  147.  
  148.             for (int x=0; x<width - n; x++)
  149.                 Buffer[y][x] = Buffer[y][x+n];
  150.  
  151.             for (; x<width; x++)
  152.                 Buffer[y][x] = 0;
  153.         }
  154.         else if ( x0 < m_lastx0 )
  155.         {
  156.             int n = m_lastx0 - x0;
  157.  
  158.             for (int x=width-1; x>n; x--)
  159.                 Buffer[y][x] = Buffer[y][x-n];
  160.  
  161.             for (; x>=0; x--)
  162.                 Buffer[y][x] = 0;
  163.         }
  164.  
  165.     m_lastx0 = x0;
  166.     m_lasty0 = y0;
  167. }
  168.  
  169. // positive reach fixed point after n iteration
  170. // negative too big           after n iternation
  171. // 0        don't know after        limit number of iterations
  172.  
  173. int KMyCanvas::MandelCount(HDC hDC, int xi, int yi, int limit)
  174. {
  175.     const double thresh  = 4.0;
  176.     const double epsilon = 0.000001;
  177.  
  178.     double x0, y0, x, y;
  179.  
  180.     x0 = m_x + m_unit * xi;
  181.     y0 = m_y + m_unit * yi;
  182.     
  183.     double oldx[5], oldy[5];
  184.  
  185.     for (int i=0; i<5; i++)
  186.     {
  187.         oldx[i] = - 100;
  188.         oldy[i] = - 100;
  189.     }
  190.  
  191. //    if ( hDC )
  192. //        MoveToEx(hDC, xi, yi, NULL);
  193.  
  194.     x = x0;
  195.     y = y0;
  196.  
  197.     for (int count=1; count<limit; count++)
  198.     {
  199.     //    if ( hDC )
  200.     //        LineTo(hDC, (int)((x-m_x)/m_unit), (int)((y-m_y)/m_unit));
  201.  
  202.         double xx = x * x;
  203.         double yy = y * y;
  204.  
  205.         double x1 = xx - yy   + x0;
  206.         double y1 = 2 * x * y + y0;
  207.  
  208.         if ( (fabs(x1-oldx[0]) < epsilon) && (fabs(y1-oldy[0]) < epsilon) )
  209.             return count;
  210.  
  211.         if ( (fabs(x1-oldx[1]) < epsilon) && (fabs(y1-oldy[1]) < epsilon) )
  212.             return count;
  213.  
  214.         if ( (fabs(x1-oldx[2]) < epsilon) && (fabs(y1-oldy[2]) < epsilon) )
  215.             return count;
  216.  
  217.         if ( (fabs(x1-oldx[3]) < epsilon) && (fabs(y1-oldy[3]) < epsilon) )
  218.             return count;
  219.  
  220.         if ( (fabs(x1-oldx[4]) < epsilon) && (fabs(y1-oldy[4]) < epsilon) )
  221.             return count;
  222.  
  223.         if ( (fabs(x1-x) < epsilon) && (fabs(y1-y) < epsilon) )
  224.             return count;
  225.  
  226.         if ( (xx + yy) > thresh )
  227.             return - count;
  228.  
  229.         oldx[0] = oldx[1]; oldx[1] = oldx[2]; oldx[2] = oldx[3]; oldx[3] = oldx[4]; oldx[4] = x;
  230.         oldy[0] = oldy[1]; oldy[1] = oldy[2]; oldy[2] = oldy[3]; oldy[3] = oldy[4]; oldy[4] = y;
  231.  
  232.         x = x1;
  233.         y = y1;
  234.     }
  235.  
  236.     return 0;
  237. }
  238.  
  239. // #define SYSRGN 4
  240.  
  241. // extern "C" BOOL WINAPI GetRandomRgn(HDC hDC, HRGN hRgn, int which);
  242.  
  243.  
  244.  
  245.  
  246. COLORREF inline Between(COLORREF from, COLORREF to, int val, int limit)
  247. {
  248.     return RGB( ( GetRValue(from) * (limit-val) + GetRValue(to) * val ) / limit,
  249.                 ( GetGValue(from) * (limit-val) + GetGValue(to) * val ) / limit,
  250.                 ( GetBValue(from) * (limit-val) + GetBValue(to) * val ) / limit
  251.               );
  252. }
  253.  
  254.  
  255. void KMyCanvas::SetLimit(int limit, BOOL bRedraw)
  256. {
  257.     m_limit = limit;
  258.  
  259.     KColor cout;
  260.     KColor cin;
  261.  
  262.     cout.red   = 0;
  263.     cout.green = 255;
  264.     cout.blue  = 64;
  265.     cout.ToHLS();
  266.  
  267.     cin.red = 244;
  268.     cin.green = 241;
  269.     cin.blue = 104;
  270.     cin.ToHLS();
  271.  
  272.     for (int i=0; i<m_limit; i++)
  273.     {
  274.         cout.hue = cout.hue + 17; 
  275.         if ( cout.hue>=360 ) cout.hue -= 360;
  276.         cout.ToRGB();
  277.  
  278.         Out[i] = RGB(cout.red, cout.green, cout.blue);
  279.  
  280.         cin.hue = cin.hue + 33; 
  281.         if ( cin.hue>=360 ) cin.hue -= 360;
  282.         cin.ToRGB();
  283.  
  284.         In[i] = RGB(cin.red, cin.green, cin.blue);
  285.     }
  286.  
  287.     if ( bRedraw )
  288.     {
  289.         InvalidateRect(m_hWnd, NULL, TRUE); 
  290.         ::UpdateWindow(m_hWnd); 
  291.     }
  292. }
  293.  
  294.  
  295. void KMyCanvas::OnDraw(HDC hDC, const RECT * rcPaint)
  296. {
  297.     if ( m_lastlimit>= m_limit )
  298.         return;
  299.  
  300.     TCHAR title [MAX_PATH];
  301.  
  302.     sprintf(title, "Mandelbrot Set (%f %f) zoom %d:%d unit %f", m_x, m_y, m_zoommul, m_zoomdiv, m_unit);
  303.     SetWindowText(GetParent(m_hWnd), title);
  304.  
  305.     int tick = GetTickCount();
  306.  
  307.     if ( rcPaint )
  308.         m_lastlimit = 0;
  309.  
  310.     RECT rect;
  311.  
  312.     GetClientRect(m_hWnd, & rect);
  313.  
  314.     int x0 = GetScrollPos(m_hWnd, SB_HORZ);
  315.     int y0 = GetScrollPos(m_hWnd, SB_VERT);
  316.  
  317. //    ClearBuffer(rect.right, rect.bottom, x0, y0);
  318.     
  319.     HRGN hRgn = CreateRectRgn(0, 0, 1, 1);
  320.  
  321.     {
  322.         GetRandomRgn(hDC, hRgn, SYSRGN);
  323.         POINT p0;
  324.         GetDCOrgEx(hDC, & p0);
  325.     
  326.         // change region to be relative to DC, NT only
  327. //        if ( HIWORD(hDC) )
  328.             OffsetRgn(hRgn, - p0.x, - p0.y);
  329.     }
  330.  
  331.     m_lastlimit += 16;
  332.  
  333.     for (int y=0; y<rect.bottom; y++) 
  334.     {
  335.         COLORREF lastc = 0xFFFFFFFF;
  336.         int         count = 0;
  337.  
  338.         for (int x=0; x<rect.right;  x++)
  339. //            if ( Buffer[y][x]==0 )
  340.             if ( PtInRegion(hRgn, x, y) )
  341.             {
  342.                 int count = MandelCount(NULL, x+x0, y+y0, m_limit);
  343.                 COLORREF c = 0;
  344.  
  345.                 if ( count==0 )        // don't know
  346.                     c = RGB(64, 78, 170);        // Red
  347.                 else if ( count>0 )    // yes
  348.                     c = In[count];    // green
  349.                 else if ( count< -3 )
  350.                     c = Out[-count]; 
  351.  
  352. //                Buffer[y][x] = count;
  353.  
  354.                 if ( c )
  355.                     SetPixel(hDC, x+x0, y+y0, c);
  356.             }
  357.     }
  358.  
  359.     tick = GetTickCount() - tick;
  360.  
  361.     wsprintf(title, "tick %d", tick);
  362.     m_pStatus->SetText(1, title);
  363. }
  364.  
  365.  
  366. void KMyCanvas::OnZoom(int x, int y, int mul, int div)
  367. {
  368.     m_unit = m_unit  / mul * div;
  369.  
  370.     KScrollCanvas::OnZoom(x, y, mul, div);
  371. }
  372.  
  373.  
  374. void KMyCanvas::OnTimer(WPARAM wParam, LPARAM lParam)
  375. {
  376. /*    HDC hDC = GetDC(m_hWnd);
  377.                 
  378.     SetWindowOrgEx(hDC, 0, 0, NULL);
  379.     SetViewportOrgEx(hDC, - GetScrollPos(m_hWnd, SB_HORZ), - GetScrollPos(m_hWnd, SB_VERT), NULL);
  380.                 
  381.     OnDraw(hDC, NULL);
  382.  
  383.     ReleaseDC(m_hWnd, hDC); */
  384. }
  385.  
  386.  
  387. void KMyCanvas::OnMouseMove(WPARAM wParam, LPARAM lParam)
  388. {
  389.     TCHAR temp[MAX_PATH];
  390.                 
  391.     int x = GetScrollPos(m_hWnd, SB_HORZ) + LOWORD(lParam);
  392.     int y = GetScrollPos(m_hWnd, SB_VERT) + HIWORD(lParam);
  393.                 
  394.     sprintf(temp, "(%f, %f) %d", m_x + x * m_unit,
  395.                                  m_y + y * m_unit,
  396.                                  MandelCount(NULL, x, y, m_limit));
  397.  
  398.        m_pStatus->SetText(0, temp);
  399. }            
  400.  
  401.  
  402. BOOL KMyCanvas::OnCommand(WPARAM wParam, LPARAM lParam)
  403. {
  404.     switch ( LOWORD(wParam) )
  405.     {
  406.         case ID_VIEW_RESET:
  407.             m_x = -2; m_y = -1; m_unit = (double) 0.0025;
  408.             InvalidateRect(m_hWnd, NULL, TRUE);
  409.             return TRUE;
  410.  
  411.         case  IDM_OPT_64 : SetLimit(   64, TRUE); return TRUE;
  412.         case  IDM_OPT_128: SetLimit(  128, TRUE); return TRUE;
  413.         case  IDM_OPT_256: SetLimit(  256, TRUE); return TRUE;
  414.         case  IDM_OPT_512: SetLimit(  512, TRUE); return TRUE;
  415.         case IDM_OPT_1024: SetLimit( 1024, TRUE); return TRUE;
  416.         case IDM_OPT_4096: SetLimit( 2048, TRUE); return TRUE;
  417.         case IDM_OPT_16384: SetLimit(16384, TRUE); return TRUE;
  418.     }
  419.  
  420.     return FALSE;
  421. }
  422.  
  423.  
  424. class KLogoFrame : public KFrame
  425. {
  426.     void GetWndClassEx(WNDCLASSEX & wc)
  427.     {
  428.         KFrame::GetWndClassEx(wc);
  429.  
  430.         wc.hIcon = LoadIcon(m_hInst, MAKEINTRESOURCE(IDI_PIXEL));
  431.     }
  432.  
  433. public:
  434.     KLogoFrame(HINSTANCE hInstance, const TBBUTTON * pButtons, int nCount,
  435.         KToolbar * pToolbar, KCanvas * pCanvas, KStatusWindow * pStatus) :
  436.             KFrame(hInstance, pButtons, nCount, pToolbar, pCanvas, pStatus)
  437.     {
  438.     }
  439.  
  440. };
  441.  
  442. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR lpCmd, int nShow)
  443. {
  444.     KMyCanvas     canvas;
  445.     KStatusWindow status;
  446.     KLogoFrame    frame(hInst, NULL, 0, NULL, & canvas, & status);
  447.  
  448. /*    double x, y;
  449.     double x0, y0;
  450.  
  451.     x0 = - 0.75;
  452.     y0 = - 0.0;
  453.     
  454.     x = x0;
  455.     y = y0;
  456.  
  457.     for (int count=1; count<=10000; count++)
  458.     {
  459.         char temp[32];
  460.  
  461.         sprintf(temp, "%6d %f %f\n", count, x, y);
  462.         OutputDebugString(temp);
  463.  
  464.         double xx = x * x;
  465.         double yy = y * y;
  466.  
  467.         double x1 = xx - yy   + x0;
  468.         double y1 = 2 * x * y + y0;
  469.  
  470.         x = x1;
  471.         y = y1;
  472.     }
  473. */
  474.     frame.CreateEx(0, _T("Mandelbrot"), _T("Mandelbrot Set"),
  475.         WS_OVERLAPPEDWINDOW,
  476.         CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
  477.         NULL, LoadMenu(hInst, MAKEINTRESOURCE(IDR_MAIN)), hInst);
  478.  
  479.     frame.ShowWindow(nShow);
  480.     frame.UpdateWindow();
  481.     frame.MessageLoop();
  482.  
  483.     return 0;
  484. }
  485.