libroot/posix/stdio: Remove unused portions.
[haiku.git] / src / apps / mandelbrot / Mandelbrot.cpp
blob054a2892ffd10de4863f48a45d9876079cd6ef9b
1 /*
2 * Copyright 2016, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license.
5 * Authors:
6 * Augustin Cavalier <waddlesplash>
7 */
10 #include <AboutWindow.h>
11 #include <Application.h>
12 #include <Bitmap.h>
13 #include <Catalog.h>
14 #include <MenuBar.h>
15 #include <LayoutBuilder.h>
16 #include <View.h>
17 #include <Window.h>
19 #include <algorithm>
21 #include "FractalEngine.h"
23 #undef B_TRANSLATION_CONTEXT
24 #define B_TRANSLATION_CONTEXT "MandelbrotWindow"
27 // #pragma mark - FractalView
30 class FractalView : public BView {
31 public:
32 FractalView();
33 ~FractalView();
35 virtual void AttachedToWindow();
36 virtual void FrameResized(float, float);
37 virtual void Pulse();
39 virtual void MouseDown(BPoint where);
40 virtual void MouseMoved(BPoint where, uint32 mode, const BMessage*);
41 virtual void MouseUp(BPoint where);
43 virtual void MessageReceived(BMessage* msg);
44 virtual void Draw(BRect updateRect);
46 void ResetPosition();
47 void RedrawFractal();
48 FractalEngine* fFractalEngine;
50 private:
51 BRect GetDragFrame();
53 bool fSizeChanged;
54 bool fOwnBitmap;
56 BPoint fSelectStart;
57 BPoint fSelectEnd;
58 bool fSelecting;
59 uint32 fMouseButtons;
61 BBitmap* fDisplayBitmap;
63 double fLocationX;
64 double fLocationY;
65 double fSize;
69 FractalView::FractalView()
71 BView(NULL, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED),
72 fFractalEngine(NULL),
73 fSizeChanged(false),
74 fOwnBitmap(false),
75 fSelecting(false),
76 fDisplayBitmap(NULL),
77 fLocationX(0),
78 fLocationY(0),
79 fSize(0.005)
81 SetHighColor(make_color(255, 255, 255, 255));
85 FractalView::~FractalView()
87 if (fOwnBitmap)
88 delete fDisplayBitmap;
92 void FractalView::ResetPosition()
94 fLocationX = 0;
95 fLocationY = 0;
96 fSize = 0.005;
100 void FractalView::AttachedToWindow()
102 fFractalEngine = new FractalEngine(this, Window());
103 fFractalEngine->Run();
104 BMessage msg(FractalEngine::MSG_RESIZE);
105 msg.AddUInt16("width", 641);
106 msg.AddUInt16("height", 462);
107 fFractalEngine->PostMessage(&msg);
108 RedrawFractal();
112 void FractalView::FrameResized(float, float)
114 fSizeChanged = true;
118 void FractalView::Pulse()
120 if (!fSizeChanged)
121 return;
122 BMessage msg(FractalEngine::MSG_RESIZE);
123 msg.AddUInt16("width", (uint16)Frame().Width() + 1);
124 msg.AddUInt16("height", (uint16)Frame().Height() + 1);
125 fFractalEngine->PostMessage(&msg);
126 // The renderer will create new bitmaps, so we own the bitmap now
127 fOwnBitmap = true;
128 fSizeChanged = false;
129 RedrawFractal();
133 BRect FractalView::GetDragFrame()
135 BRect dragZone = BRect(std::min(fSelectStart.x, fSelectEnd.x),
136 std::min(fSelectStart.y, fSelectEnd.y),
137 std::max(fSelectStart.x, fSelectEnd.x),
138 std::max(fSelectStart.y, fSelectEnd.y)),
139 frame = Frame();
140 float width = dragZone.Width(),
141 height = width * (frame.Height() / frame.Width());
143 float x1 = fSelectStart.x, y1 = fSelectStart.y, x2, y2;
144 if (fSelectStart.x < fSelectEnd.x)
145 x2 = x1 + width;
146 else
147 x2 = x1 - width;
148 if (fSelectStart.y < fSelectEnd.y)
149 y2 = y1 + height;
150 else
151 y2 = y1 - height;
152 return BRect(x1, y1, x2, y2);
156 void FractalView::MouseDown(BPoint where)
158 fSelecting = true;
159 fSelectStart = where;
160 fMouseButtons = 0;
161 Window()->CurrentMessage()->FindInt32("buttons", (int32*)&fMouseButtons);
165 void FractalView::MouseMoved(BPoint where, uint32 mode, const BMessage*)
167 if (fSelecting) {
168 fSelectEnd = where;
169 Invalidate();
174 void FractalView::MouseUp(BPoint where)
176 BRect frame = Frame();
177 fSelecting = false;
178 if (fabs(fSelectStart.x - where.x) > 4) {
179 fSelectEnd = where;
180 BRect dragFrame = GetDragFrame();
181 BPoint lt = dragFrame.LeftTop();
182 float centerX = lt.x + dragFrame.Width() / 2,
183 centerY = lt.y + dragFrame.Height() / 2;
184 fLocationX = ((centerX - frame.Width() / 2) * fSize + fLocationX);
185 fLocationY = ((centerY - frame.Height() / 2) * -fSize + fLocationY);
187 fSize = (dragFrame.Width() * fSize) / frame.Width();
188 } else {
189 fLocationX = ((where.x - frame.Width() / 2) * fSize + fLocationX);
190 fLocationY = ((where.y - frame.Height() / 2) * -fSize + fLocationY);
191 if (fMouseButtons & B_PRIMARY_MOUSE_BUTTON)
192 fSize /= 2;
193 else
194 fSize *= 2;
196 RedrawFractal();
200 void FractalView::MessageReceived(BMessage* msg)
202 switch (msg->what) {
203 case B_MOUSE_WHEEL_CHANGED: {
204 float change = msg->FindFloat("be:wheel_delta_y");
205 BPoint where;
206 GetMouse(&where, NULL);
207 BRect frame = Frame();
208 fLocationX = ((where.x - frame.Width() / 2) * fSize + fLocationX);
209 fLocationY = ((where.y - frame.Height() / 2) * -fSize + fLocationY);
210 if (change < 0)
211 fSize /= 1.5;
212 else
213 fSize *= 1.5;
214 RedrawFractal();
215 break;
218 case FractalEngine::MSG_RENDER_COMPLETE:
219 if (fOwnBitmap) {
220 fOwnBitmap = false;
221 delete fDisplayBitmap;
223 fDisplayBitmap = NULL; // In case the following line fails
224 msg->FindPointer("bitmap", (void**)&fDisplayBitmap);
225 Invalidate();
226 break;
228 default:
229 BView::MessageReceived(msg);
230 break;
235 void FractalView::RedrawFractal()
237 BMessage message(FractalEngine::MSG_RENDER);
238 message.AddDouble("locationX", fLocationX);
239 message.AddDouble("locationY", fLocationY);
240 message.AddDouble("size", fSize);
241 fFractalEngine->PostMessage(&message);
245 void FractalView::Draw(BRect updateRect)
247 DrawBitmap(fDisplayBitmap, updateRect, updateRect);
249 if (fSelecting) {
250 StrokeRect(GetDragFrame());
255 // #pragma mark - MandelbrotWindow
258 class MandelbrotWindow : public BWindow
260 public:
261 enum {
262 MSG_MANDELBROT_SET = 'MndW',
263 MSG_BURNINGSHIP_SET,
264 MSG_TRICORN_SET,
265 MSG_JULIA_SET,
266 MSG_ORBITTRAP_SET,
267 MSG_MULTIBROT_SET,
269 MSG_ROYAL_PALETTE,
270 MSG_DEEPFROST_PALETTE,
271 MSG_FROST_PALETTE,
272 MSG_FIRE_PALETTE,
273 MSG_MIDNIGHT_PALETTE,
274 MSG_GRASSLAND_PALETTE,
275 MSG_LIGHTNING_PALETTE,
276 MSG_SPRING_PALETTE,
277 MSG_HIGHCONTRAST_PALETTE,
279 MSG_ITER_128,
280 MSG_ITER_512,
281 MSG_ITER_1024,
282 MSG_ITER_4096,
283 MSG_ITER_8192,
284 MSG_ITER_12288,
285 MSG_ITER_16384
287 MandelbrotWindow(BRect frame);
288 ~MandelbrotWindow() {}
290 virtual void MessageReceived(BMessage* msg);
291 virtual bool QuitRequested();
293 private:
294 FractalView* fFractalView;
298 MandelbrotWindow::MandelbrotWindow(BRect frame)
300 BWindow(frame, B_TRANSLATE_SYSTEM_NAME("Mandelbrot"), B_TITLED_WINDOW_LOOK,
301 B_NORMAL_WINDOW_FEEL, 0L),
302 fFractalView(new FractalView)
304 SetPulseRate(250000); // pulse twice per second
306 BMenuBar* menuBar = new BMenuBar("MenuBar");
307 BMenu* setMenu;
308 BMenu* paletteMenu;
309 BMenu* iterMenu;
310 BLayoutBuilder::Menu<>(menuBar)
311 .AddMenu(B_TRANSLATE("File"))
312 .AddItem(B_TRANSLATE("About"), B_ABOUT_REQUESTED)
313 .AddItem(B_TRANSLATE("Quit"), B_QUIT_REQUESTED, 'Q')
314 .End()
315 .AddMenu(B_TRANSLATE("Set"))
316 .GetMenu(setMenu)
317 .AddItem(B_TRANSLATE("Mandelbrot"), MSG_MANDELBROT_SET)
318 .AddItem(B_TRANSLATE("Burning Ship"), MSG_BURNINGSHIP_SET)
319 .AddItem(B_TRANSLATE("Tricorn"), MSG_TRICORN_SET)
320 .AddItem(B_TRANSLATE("Julia"), MSG_JULIA_SET)
321 .AddItem(B_TRANSLATE("Orbit Trap"), MSG_ORBITTRAP_SET)
322 .AddItem(B_TRANSLATE("Multibrot"), MSG_MULTIBROT_SET)
323 .End()
324 .AddMenu(B_TRANSLATE("Palette"))
325 .GetMenu(paletteMenu)
326 .AddItem(B_TRANSLATE("Royal"), MSG_ROYAL_PALETTE)
327 .AddItem(B_TRANSLATE("Deepfrost"), MSG_DEEPFROST_PALETTE)
328 .AddItem(B_TRANSLATE("Frost"), MSG_FROST_PALETTE)
329 .AddItem(B_TRANSLATE("Fire"), MSG_FIRE_PALETTE)
330 .AddItem(B_TRANSLATE("Midnight"), MSG_MIDNIGHT_PALETTE)
331 .AddItem(B_TRANSLATE("Grassland"), MSG_GRASSLAND_PALETTE)
332 .AddItem(B_TRANSLATE("Lightning"), MSG_LIGHTNING_PALETTE)
333 .AddItem(B_TRANSLATE("Spring"), MSG_SPRING_PALETTE)
334 .AddItem(B_TRANSLATE("High contrast"), MSG_HIGHCONTRAST_PALETTE)
335 .End()
336 .AddMenu(B_TRANSLATE("Iterations"))
337 .GetMenu(iterMenu)
338 .AddItem("128", MSG_ITER_128)
339 .AddItem("512", MSG_ITER_512)
340 .AddItem("1024", MSG_ITER_1024)
341 .AddItem("4096", MSG_ITER_4096)
342 .AddItem("8192", MSG_ITER_8192)
343 .AddItem("12288", MSG_ITER_12288)
344 .AddItem("16384", MSG_ITER_16384)
345 .End()
346 .End();
347 setMenu->SetRadioMode(true);
348 setMenu->FindItem(MSG_MANDELBROT_SET)->SetMarked(true);
349 paletteMenu->SetRadioMode(true);
350 paletteMenu->FindItem(MSG_ROYAL_PALETTE)->SetMarked(true);
351 iterMenu->SetRadioMode(true);
352 iterMenu->FindItem(MSG_ITER_1024)->SetMarked(true);
354 BLayoutBuilder::Group<>(this, B_VERTICAL, 0)
355 .SetInsets(0)
356 .Add(menuBar)
357 .Add(fFractalView)
358 .End();
362 #define HANDLE_SET(uiwhat, id) \
363 case uiwhat: { \
364 BMessage msg(FractalEngine::MSG_CHANGE_SET); \
365 msg.AddUInt8("set", id); \
366 fFractalView->fFractalEngine->PostMessage(&msg); \
367 fFractalView->ResetPosition(); \
368 fFractalView->RedrawFractal(); \
369 break; \
371 #define HANDLE_PALETTE(uiwhat, id) \
372 case uiwhat: { \
373 BMessage msg(FractalEngine::MSG_SET_PALETTE); \
374 msg.AddUInt8("palette", id); \
375 fFractalView->fFractalEngine->PostMessage(&msg); \
376 fFractalView->RedrawFractal(); \
377 break; \
379 #define HANDLE_ITER(uiwhat, id) \
380 case uiwhat: { \
381 BMessage msg(FractalEngine::MSG_SET_ITERATIONS); \
382 msg.AddUInt16("iterations", id); \
383 fFractalView->fFractalEngine->PostMessage(&msg); \
384 fFractalView->RedrawFractal(); \
385 break; \
387 void
388 MandelbrotWindow::MessageReceived(BMessage* msg)
390 switch (msg->what) {
391 HANDLE_SET(MSG_MANDELBROT_SET, 0)
392 HANDLE_SET(MSG_BURNINGSHIP_SET, 1)
393 HANDLE_SET(MSG_TRICORN_SET, 2)
394 HANDLE_SET(MSG_JULIA_SET, 3)
395 HANDLE_SET(MSG_ORBITTRAP_SET, 4)
396 HANDLE_SET(MSG_MULTIBROT_SET, 5)
398 HANDLE_PALETTE(MSG_ROYAL_PALETTE, 0)
399 HANDLE_PALETTE(MSG_DEEPFROST_PALETTE, 1)
400 HANDLE_PALETTE(MSG_FROST_PALETTE, 2)
401 HANDLE_PALETTE(MSG_FIRE_PALETTE, 3)
402 HANDLE_PALETTE(MSG_MIDNIGHT_PALETTE, 4)
403 HANDLE_PALETTE(MSG_GRASSLAND_PALETTE, 5)
404 HANDLE_PALETTE(MSG_LIGHTNING_PALETTE, 6)
405 HANDLE_PALETTE(MSG_SPRING_PALETTE, 7)
406 HANDLE_PALETTE(MSG_HIGHCONTRAST_PALETTE, 8)
408 HANDLE_ITER(MSG_ITER_128, 128)
409 HANDLE_ITER(MSG_ITER_512, 512)
410 HANDLE_ITER(MSG_ITER_1024, 1024)
411 HANDLE_ITER(MSG_ITER_4096, 4096)
412 HANDLE_ITER(MSG_ITER_8192, 8192)
413 HANDLE_ITER(MSG_ITER_12288, 12288)
414 HANDLE_ITER(MSG_ITER_16384, 16384)
416 case B_ABOUT_REQUESTED: {
417 BAboutWindow* wind = new BAboutWindow("Mandelbrot", "application/x-vnd.Haiku-Mandelbrot");
418 const char* authors[] = {
419 "Augustin Cavalier <waddlesplash>",
420 B_TRANSLATE("kerwizzy (original FractalEngine author)"),
421 NULL
423 wind->AddCopyright(2016, "Haiku, Inc.");
424 wind->AddAuthors(authors);
425 wind->Show();
426 break;
429 default:
430 BWindow::MessageReceived(msg);
431 break;
434 #undef HANDLE_SET
435 #undef HANDLE_PALETTE
436 #undef HANDLE_ITER
439 bool
440 MandelbrotWindow::QuitRequested()
442 if (BWindow::QuitRequested()) {
443 be_app->PostMessage(B_QUIT_REQUESTED);
444 return true;
446 return false;
450 // #pragma mark - MandelbrotApp
453 class MandelbrotApp : public BApplication
455 public:
456 MandelbrotApp()
457 : BApplication("application/x-vnd.Haiku-Mandelbrot") {}
459 void ReadyToRun();
460 bool QuitRequested() { return true; }
464 void
465 MandelbrotApp::ReadyToRun()
467 MandelbrotWindow* wind = new MandelbrotWindow(BRect(0, 0, 640, 480));
468 wind->CenterOnScreen();
469 wind->Show();
474 main(int argc, char* argv[])
476 MandelbrotApp().Run();
477 return 0;