1///////////////////////////////////////////////////////////////////////////////
2// Name:        fractal.cpp
3// Purpose:     demo of wxConfig and related classes
4// Author:      Andrew Davison
5// Modified by:
6// Created:     05.04.94
7// RCS-ID:      $Id: fractal.cpp 35650 2005-09-23 12:56:45Z MR $
8// Copyright:   (c) 1994 Andrew Davison
9// Licence:     wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12
13/*
14Date: Tue, 5 Apr 1994 12:01:18 +1000
15From: Andrew Davison <andrewd@au.com.sfe>
16To: wxwin-users@ed.aiai
17Subject: Fractal mountains
18
19Hi,
20
21This is a quick port of a fractal mountain generator originally
22done for MS-Windows. On a Sun the colours look a little washed
23out and there is not as much snow or high mountains (maybe the
24random number generators fault). The viewing plane is not
25quite right as the original code used SetViewportOrg() which there
26doesn't seem to be an equivalent of under wxWidgets, and my quick
27hack doesn't fix.
28*/
29
30#include "wx/wxprec.h"
31
32#ifdef __BORLANDC__
33    #pragma hdrstop
34#endif
35
36#ifndef  WX_PRECOMP
37  #include "wx/wx.h"
38#endif //precompiled headers
39
40#include "wx/math.h"
41#include "wx/stockitem.h"
42
43#include <stdlib.h>
44#include <time.h>
45
46#define Random(x) (rand() % x)
47#define Randomize() (srand((unsigned int)time(NULL)))
48
49static int detail = 9; // CHANGE THIS... 7,8,9 etc
50
51static bool running = false;
52static wxMenuBar *menuBar = NULL;
53
54// Define a new application type
55class MyApp: public wxApp
56{
57public:
58    bool OnInit();
59};
60
61IMPLEMENT_APP(MyApp)
62
63// Define a new frame type
64class MyFrame: public wxFrame
65{
66public:
67    MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size);
68
69    void OnCloseWindow(wxCloseEvent& event);
70    void OnExit(wxCommandEvent& event);
71
72    DECLARE_EVENT_TABLE()
73};
74
75// Define a new canvas which can receive some events
76class MyCanvas: public wxWindow
77{
78public:
79    MyCanvas(wxFrame *frame);
80    void Draw(wxDC& dc);
81
82private:
83    void OnPaint(wxPaintEvent& event);
84    void Fractal(wxDC& dc, int X1, int Y1, int X2, int Y2, int Z1, int Z2, int Z3, int Z4, int Iteration, double Std, double Ratio);
85    wxPen SnowPen, MtnPen, GreenPen;
86    wxBrush WaterBrush;
87    int Sealevel;
88
89DECLARE_EVENT_TABLE()
90};
91
92// `Main program' equivalent, creating windows and returning main app frame
93bool MyApp::OnInit()
94{
95  // Create the main frame window
96  MyFrame *frame = new MyFrame(NULL, _T("Fractal Mountains for wxWidgets"), wxDefaultPosition, wxSize(640, 480));
97
98  // Make a menubar
99  wxMenu *file_menu = new wxMenu;
100  file_menu->Append(wxID_EXIT, wxGetStockLabel(wxID_EXIT));
101  menuBar = new wxMenuBar;
102  menuBar->Append(file_menu, _T("&File"));
103  frame->SetMenuBar(menuBar);
104
105  int width, height;
106  frame->GetClientSize(&width, &height);
107
108  (void) new MyCanvas(frame);
109
110  // Show the frame
111  frame->Show(true);
112
113  return true;
114}
115
116BEGIN_EVENT_TABLE(MyFrame, wxFrame)
117  EVT_CLOSE(MyFrame::OnCloseWindow)
118  EVT_MENU(wxID_EXIT, MyFrame::OnExit)
119END_EVENT_TABLE()
120
121// My frame constructor
122MyFrame::MyFrame(wxFrame *frame, const wxString& title, const wxPoint& pos, const wxSize& size):
123  wxFrame(frame, wxID_ANY, title, pos, size, wxDEFAULT_FRAME_STYLE | wxFULL_REPAINT_ON_RESIZE )
124{
125}
126
127// Intercept menu commands
128void MyFrame::OnExit(wxCommandEvent& WXUNUSED(event))
129{
130    this->Destroy();
131}
132
133void MyFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
134{
135    static bool destroyed = false;
136    if (destroyed)
137        return;
138
139    this->Destroy();
140
141    destroyed = true;
142}
143
144BEGIN_EVENT_TABLE(MyCanvas, wxWindow)
145  EVT_PAINT(MyCanvas::OnPaint)
146END_EVENT_TABLE()
147
148// Define a constructor for my canvas
149MyCanvas::MyCanvas(wxFrame *frame):
150 wxWindow(frame, wxID_ANY)
151{
152    wxColour wxCol1(255,255,255);
153    SnowPen = wxPen(wxCol1, 2, wxSOLID);
154
155    wxColour wxCol2(128,0,0);
156    MtnPen = wxPen(wxCol2, 1, wxSOLID);
157
158    wxColour wxCol3(0,128,0);
159    GreenPen = wxPen(wxCol3, 1, wxSOLID);
160
161    wxColour wxCol4(0,0,128);
162    WaterBrush = wxBrush(wxCol4, wxSOLID);
163}
164
165void MyCanvas::OnPaint(wxPaintEvent& WXUNUSED(event))
166{
167    wxPaintDC dc(this);
168    PrepareDC(dc);
169    Draw(dc);
170}
171
172void MyCanvas::Draw(wxDC& dc)
173{
174    if (running) return;
175
176    running = true;
177    menuBar->EnableTop(0, false);
178
179    Randomize();
180
181    dc.SetBackground(*wxLIGHT_GREY_BRUSH);
182    dc.Clear();
183
184    int Left, Top, Right, Bottom;
185    GetClientSize(&Right, &Bottom);
186
187    Right *= 3; Right /= 4;
188    Bottom *= 3; Bottom /= 4;
189    Left = 0;
190    Top = Bottom/8;
191
192    wxPoint Water[4];
193    Water[0].x = Left;            Water[0].y = Top;
194    Water[1].x = Right;           Water[1].y = Top;
195    Water[2].x = Right+Bottom/2;  Water[2].y = Bottom;
196    Water[3].x = Bottom/2;        Water[3].y = Bottom;
197
198    dc.SetBrush(WaterBrush);
199    dc.DrawPolygon(4, Water);
200
201    double H = 0.75;
202    double Scale = Bottom;
203    double Ratio = 1.0 / pow(2.0, H);
204    double Std = Scale * Ratio;
205    Sealevel = Random(18) - 8;
206
207    Fractal(dc, Left, Top, Right, Bottom, 0, 0, 0, 0, detail, Std, Ratio);
208
209    menuBar->EnableTop(0, true);
210    running = false;
211}
212
213void MyCanvas::Fractal(wxDC& dc, int X1, int Y1, int X2, int Y2, int Z1, int Z2, int Z3, int Z4, int Iteration, double Std, double Ratio)
214{
215    int Xmid = (X1 + X2) / 2;
216    int Ymid = (Y1 + Y2) / 2;
217    int Z23 = (Z2 + Z3) / 2;
218    int Z41 = (Z4 + Z1) / 2;
219    int Newz = (int)((Z1 + Z2 + Z3 + Z4) / 4 + (double)(Random(17) - 8) / 8.0 * Std);
220
221    if (--Iteration)
222    {
223        int Z12 = (Z1 + Z2) / 2;
224        int Z34 = (Z3 + Z4) / 2;
225        double Stdmid = Std * Ratio;
226
227        Fractal(dc, Xmid, Y1, X2, Ymid, Z12, Z2, Z23, Newz, Iteration, Stdmid, Ratio);
228        Fractal(dc, X1, Y1, Xmid, Ymid, Z1, Z12, Newz, Z41, Iteration, Stdmid, Ratio);
229        Fractal(dc, Xmid, Ymid, X2, Y2, Newz, Z23, Z3, Z34, Iteration, Stdmid, Ratio);
230        Fractal(dc, X1, Ymid, Xmid, Y2, Z41, Newz, Z34, Z4, Iteration, Stdmid, Ratio);
231    }
232    else
233    {
234        if (Newz <= Sealevel)
235        {
236            wxPoint P[4];
237            P[0].x = Y1 / 2 + X1;    P[0].y = Y1 + Z1;
238            P[1].x = Y1 / 2 + X2;    P[1].y = Y1 + Z2;
239            P[2].x = Y2 / 2 + X2;    P[2].y = Y2 + Z3;
240            P[3].x = Y2 / 2 + X1;    P[3].y = Y2 + Z4;
241
242            dc.SetPen(* wxBLACK_PEN);
243            dc.SetBrush(* wxBLACK_BRUSH);
244
245            dc.DrawPolygon(4, P);
246
247            if (Z1 >= -(60+Random(25)))
248                dc.SetPen(GreenPen);
249            else if (Z1 >= -(100+Random(25)))
250                dc.SetPen(MtnPen);
251            else
252                dc.SetPen(SnowPen);
253
254            dc.DrawLine(Ymid/2+X2, Ymid+Z23, Ymid/2+X1, Ymid+Z41);
255        }
256    }
257}
258
259