1 /**
2 * Mandelbulber v2, a 3D fractal generator ,=#MKNmMMKmmßMNWy,
3 * ,B" ]L,,p%%%,,,§;, "K
4 * Copyright (C) 2014-21 Mandelbulber Team §R-==%w["'~5]m%=L.=~5N
5 * ,=mm=§M ]=4 yJKA"/-Nsaj "Bw,==,,
6 * This file is part of Mandelbulber. §R.r= jw",M Km .mM FW ",§=ß., ,TN
7 * ,4R =%["w[N=7]J '"5=],""]]M,w,-; T=]M
8 * Mandelbulber is free software: §R.ß~-Q/M=,=5"v"]=Qf,'§"M= =,M.§ Rz]M"Kw
9 * you can redistribute it and/or §w "xDY.J ' -"m=====WeC=\ ""%""y=%"]"" §
10 * modify it under the terms of the "§M=M =D=4"N #"%==A%p M§ M6 R' #"=~.4M
11 * GNU General Public License as §W =, ][T"]C § § '§ e===~ U !§[Z ]N
12 * published by the 4M",,Jm=,"=e~ § § j]]""N BmM"py=ßM
13 * Free Software Foundation, ]§ T,M=& 'YmMMpM9MMM%=w=,,=MT]M m§;'§,
14 * either version 3 of the License, TWw [.j"5=~N[=§%=%W,T ]R,"=="Y[LFT ]N
15 * or (at your option) TW=,-#"%=;[ =Q:["V"" ],,M.m == ]N
16 * any later version. J§"mr"] ,=,," =="""J]= M"M"]==ß"
17 * §= "=C=4 §"eM "=B:m|4"]#F,§~
18 * Mandelbulber is distributed in "9w=,,]w em%wJ '"~" ,=,,ß"
19 * the hope that it will be useful, . "K= ,=RMMMßM"""
20 * but WITHOUT ANY WARRANTY; .'''
21 * without even the implied warranty
22 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23 *
24 * See the GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with Mandelbulber. If not, see <http://www.gnu.org/licenses/>.
27 *
28 * ###########################################################################
29 *
30 * Authors: Krzysztof Marczak (buddhi1980@gmail.com), Sebastian Jennen (jenzebas@gmail.com)
31 *
32 * cInterface class - operations connected directly with user interface
33 */
34
35 #include "interface.hpp"
36
37 #include "ui_render_window.h"
38
39 #include "animation_flight.hpp"
40 #include "animation_keyframes.hpp"
41 #include "ao_modes.h"
42 #include "automated_widgets.hpp"
43 #include "calculate_distance.hpp"
44 #include "camera_movement_modes.h"
45 #include "camera_target.hpp"
46 #include "common_math.h"
47 #include "dof.hpp"
48 #include "error_message.hpp"
49 #include "fractparams.hpp"
50 #include "global_data.hpp"
51 #include "headless.h"
52 #include "initparameters.hpp"
53 #include "lights.hpp"
54 #include "material_item_model.h"
55 #include "my_ui_loader.h"
56 #include "netrender.hpp"
57 #include "nine_fractals.hpp"
58 #include "opencl_engine_render_dof.h"
59 #include "opencl_engine_render_fractal.h"
60 #include "opencl_engine_render_post_filter.h"
61 #include "opencl_engine_render_ssao.h"
62 #include "opencl_global.h"
63 #include "post_effect_hdr_blur.h"
64 #include "queue.hpp"
65 #include "random.hpp"
66 #include "randomizer_dialog.h"
67 #include "render_data.hpp"
68 #include "render_job.hpp"
69 #include "render_ssao.h"
70 #include "render_window.hpp"
71 #include "rendered_image_widget.hpp"
72 #include "rendering_configuration.hpp"
73 #include "settings.hpp"
74 #include "system_data.hpp"
75 #include "trace_behind.h"
76 #include "tree_string_list.h"
77 #include "undo.h"
78 #include "write_log.hpp"
79
80 #include "qt/detached_window.h"
81 #include "qt/dock_effects.h"
82 #include "qt/material_editor.h"
83 #include "qt/my_group_box.h"
84 #include "qt/my_progress_bar.h"
85 #include "qt/player_widget.hpp"
86 #include "qt/preview_file_dialog.h"
87 #include "qt/settings_cleaner.h"
88 #include "qt/system_tray.hpp"
89
90 // custom includes
91 #ifdef USE_GAMEPAD
92 #include <QtGamepad/qgamepadmanager.h>
93 #endif // USE_GAMEPAD
94
95 cInterface *gMainInterface = nullptr;
96
97 // constructor of interface (loading of ui files)
cInterface(QObject * parent)98 cInterface::cInterface(QObject *parent) : QObject(parent)
99 {
100 mainWindow = nullptr;
101 detachedWindow = nullptr;
102 headless = nullptr;
103 renderedImage = nullptr;
104 imageSequencePlayer = nullptr;
105 mainImage = nullptr;
106 progressBar = nullptr;
107 progressBarAnimation = nullptr;
108 progressBarQueueImage = nullptr;
109 progressBarQueueAnimation = nullptr;
110 progressBarFrame = nullptr;
111 progressBarLayout = nullptr;
112 autoRefreshTimer = nullptr;
113 stopRequestPulseTimer = nullptr;
114 materialListModel = nullptr;
115 materialEditor = nullptr;
116 scrollAreaMaterialEditor = nullptr;
117 systemTray = nullptr;
118 stopRequest = false;
119 repeatRequest = false;
120 autoRefreshLastState = false;
121 lockedDetailLevel = 1.0;
122 lastSelectedMaterial = 1;
123 numberOfStartedRenders = 0;
124 }
125
~cInterface()126 cInterface::~cInterface()
127 {
128 if (imageSequencePlayer) delete imageSequencePlayer;
129 if (mainWindow) delete mainWindow;
130 }
131
ShowUi()132 void cInterface::ShowUi()
133 {
134 WriteLog("Prepare RenderWindow class", 2);
135
136 QFont font = gApplication->font();
137 font.setPointSizeF(gPar->Get<int>("ui_font_size"));
138 gApplication->setFont(font);
139
140 QFontMetrics fm(gApplication->font());
141 int pixelFontSize = fm.height();
142
143 int thumbnailSize = (pixelFontSize * 8);
144
145 systemData.SetPreferredFontSize(pixelFontSize);
146 systemData.SetPreferredThumbnailSize(thumbnailSize);
147
148 systemData.setPreferredCustomFormulaFontSize(gPar->Get<int>("custom_formula_font_size"));
149
150 mainWindow = new RenderWindow();
151
152 WriteLog("Restoring window geometry", 2);
153
154 if (gPar->Get<bool>("image_detached"))
155 {
156 DetachMainImageWidget();
157 mainWindow->ui->actionDetach_image_from_main_window->setChecked(true);
158 }
159
160 mainWindow->restoreGeometry(settings.value("mainWindowGeometry").toByteArray());
161
162 WriteLog("Restoring window state", 2);
163
164 if (!mainWindow->restoreState(settings.value("mainWindowState").toByteArray()))
165 {
166 mainWindow->tabifyDockWidget(
167 mainWindow->ui->dockWidget_materialEditor, mainWindow->ui->dockWidget_effects);
168 mainWindow->tabifyDockWidget(
169 mainWindow->ui->dockWidget_effects, mainWindow->ui->dockWidget_image_adjustments);
170 mainWindow->tabifyDockWidget(
171 mainWindow->ui->dockWidget_image_adjustments, mainWindow->ui->dockWidget_rendering_engine);
172 mainWindow->tabifyDockWidget(
173 mainWindow->ui->dockWidget_rendering_engine, mainWindow->ui->dockWidget_objects);
174 mainWindow->ui->dockWidget_animation->hide();
175 mainWindow->ui->dockWidget_info->hide();
176 mainWindow->ui->dockWidget_gamepad_dock->hide();
177 mainWindow->ui->dockWidget_histogram->hide();
178 mainWindow->ui->dockWidget_queue_dock->hide();
179 }
180
181 mainWindow->setFont(font);
182
183 #ifdef __APPLE__
184 mainWindow->ui->actionAbout_Qt->setText(QApplication::translate("RenderWindow", "Info &Qt", 0));
185 mainWindow->ui->actionAbout_Manual->setText(
186 QApplication::translate("RenderWindow", "About &User Manual", 0));
187 mainWindow->ui->actionAbout_Mandelbulber->setText(
188 QApplication::translate("RenderWindow", "&Info Mandelbulber", 0));
189 mainWindow->ui->actionAbout_ThirdParty->setText(
190 QApplication::translate("RenderWindow", "Info &Third Party", 0));
191 #endif
192
193 WriteLog("mainWindow->show()", 2);
194 mainWindow->show();
195
196 WriteLog("Prepare RenderedImage class", 2);
197 renderedImage = new RenderedImage(mainWindow);
198
199 mainWindow->ui->scrollAreaLayoutRenderedImage->addWidget(renderedImage);
200
201 // setup main image
202 WriteLog("Setup of main image", 2);
203 mainImage.reset(new cImage(gPar->Get<int>("image_width"), gPar->Get<int>("image_height")));
204 mainImage->CreatePreview(1.0, 800, 600, renderedImage);
205 mainImage->CompileImage();
206 mainImage->ConvertTo8bitChar();
207 mainImage->UpdatePreview();
208 mainImage->SetAsMainImage();
209 renderedImage->setMinimumSize(
210 int(mainImage->GetPreviewWidth()), int(mainImage->GetPreviewHeight()));
211 renderedImage->AssignImage(mainImage);
212 renderedImage->AssignParameters(gPar, gParFractal);
213
214 WriteLog("Prepare progress and status bar", 2);
215 progressBarLayout = new QVBoxLayout();
216 progressBarLayout->setSpacing(0);
217 progressBarLayout->setContentsMargins(0, 0, 0, 0);
218 progressBarFrame = new QFrame(mainWindow->ui->statusbar);
219
220 progressBarQueueImage = mainWindow->ui->widgetDockQueue->GetProgressBarImage();
221 progressBarQueueAnimation = mainWindow->ui->widgetDockQueue->GetProgressBarAnimation();
222
223 progressBarAnimation = new MyProgressBar(progressBarFrame);
224 progressBarAnimation->setMaximum(1000);
225 progressBarAnimation->setAlignment(Qt::AlignCenter);
226 progressBarAnimation->hide();
227 progressBarLayout->addWidget(progressBarAnimation);
228
229 progressBar = new MyProgressBar(progressBarFrame);
230 progressBar->setMaximum(1000);
231 progressBar->setAlignment(Qt::AlignCenter);
232 progressBarLayout->addWidget(progressBar);
233
234 QFrame *progressBarFrameInternal = new QFrame(mainWindow->ui->statusbar);
235 progressBarFrameInternal->setLayout(progressBarLayout);
236 mainWindow->ui->statusbar->addPermanentWidget(progressBarFrameInternal);
237
238 mainWindow->setWindowTitle(QString("Mandelbulber (") + systemData.lastSettingsFile + ")");
239
240 #ifndef USE_EXR
241 {
242 mainWindow->ui->actionSave_as_EXR->setVisible(false);
243 mainWindow->ui->widgetDockAnimation->DisableEXR();
244 }
245 #endif
246
247 #ifndef USE_TIFF
248 {
249 mainWindow->ui->actionSave_as_TIFF->setVisible(false);
250 mainWindow->ui->widgetDockAnimation->DisableTIFF();
251 }
252 #endif
253
254 #ifndef USE_GAMEPAD
255 {
256 delete mainWindow->ui->dockWidget_gamepad_dock;
257 mainWindow->ui->dockWidget_gamepad_dock = nullptr;
258 }
259 #endif
260
261 #ifndef USE_OPENCL
262 mainWindow->GetWidgetDockNavigation()->EnableOpenCLModeComboBox(false);
263 #else
264 mainWindow->GetWidgetDockNavigation()->EnableOpenCLModeComboBox(
265 gPar->Get<bool>("opencl_enabled"));
266
267 if (gPar->Get<bool>("opencl_enabled") && gPar->Get<bool>("opencl_mode") > 0)
268 mainWindow->GetWidgetDockImageAdjustments()->SetAntialiasingOpenCL(true);
269 #endif
270
271 QShortcut *shortcut = new QShortcut(QKeySequence(Qt::Key_F11), mainWindow);
272 shortcut->setContext(Qt::ApplicationShortcut);
273 connect(shortcut, &QShortcut::activated, mainWindow, &RenderWindow::ToggleFullScreen);
274
275 mainWindow->ui->actionImport_settings_from_Mandelbulb3d->setVisible(false);
276
277 if (gPar->Get<bool>("ui_colorize"))
278 ColorizeGroupBoxes(mainWindow, gPar->Get<int>("ui_colorize_random_seed"));
279
280 renderedImage->show();
281
282 mainWindow->setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
283 mainWindow->setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
284 mainWindow->setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
285 mainWindow->setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
286
287 // loading default ui for all fractal components
288 mainWindow->ui->widgetDockFractal->InitializeFractalUi();
289 InitMaterialsUi();
290 scrollAreaMaterialEditor = mainWindow->ui->scrollArea_material;
291
292 // change some default settings with keeping compatibility with older versions
293 StartupDefaultSettings();
294
295 systemData.numberOfThreads = gPar->Get<int>("limit_CPU_cores");
296 systemData.threadsPriority = enumRenderingThreadPriority(gPar->Get<int>("threads_priority"));
297
298 ComboMouseClickUpdate();
299
300 mainWindow->slotPopulateRecentSettings();
301 mainWindow->slotPopulateCustomWindowStates();
302 systemTray = new cSystemTray(mainImage, mainWindow);
303
304 // installing event filter for disabling tooltips
305 gApplication->installEventFilter(mainWindow);
306
307 WriteLog("cInterface::ConnectSignals(void)", 2);
308 ConnectSignals();
309 WriteLog("cInterface::ConnectSignals(void) finished", 2);
310 }
311
ConnectSignals() const312 void cInterface::ConnectSignals() const
313 {
314 // other
315
316 connect(mainWindow->ui->checkBox_show_cursor, SIGNAL(stateChanged(int)), mainWindow,
317 SLOT(slotChangedCheckBoxCursorVisibility(int)));
318
319 connect(mainWindow->ui->comboBox_mouse_click_function, SIGNAL(currentIndexChanged(int)),
320 mainWindow, SLOT(slotChangedComboMouseClickFunction(int)));
321
322 connect(mainWindow->ui->comboBox_grid_type, SIGNAL(currentIndexChanged(int)), mainWindow,
323 SLOT(slotChangedComboGridType(int)));
324
325 connect(mainWindow, SIGNAL(AppendToLog(const QString &)), mainWindow->ui->log_text,
326 SLOT(appendMessage(const QString &)));
327
328 // menu actions
329 connect(mainWindow->ui->actionQuit, &QAction::triggered, mainWindow, &RenderWindow::slotQuit);
330 connect(mainWindow->ui->actionSave_docks_positions, &QAction::triggered, mainWindow,
331 &RenderWindow::slotMenuSaveDocksPositions);
332 connect(mainWindow->ui->actionDefault_docks_positions, &QAction::triggered, mainWindow,
333 &RenderWindow::slotMenuResetDocksPositions);
334 connect(mainWindow->ui->actionAnimation_docks_positions, &QAction::triggered, mainWindow,
335 &RenderWindow::slotMenuAnimationDocksPositions);
336 connect(mainWindow->ui->actionStack_all_docks, &QAction::triggered, mainWindow,
337 &RenderWindow::slotStackAllDocks);
338 connect(mainWindow->ui->actionShow_animation_dock, &QAction::triggered, mainWindow,
339 &RenderWindow::slotUpdateDocksAndToolbarByAction);
340 connect(mainWindow->ui->actionShow_toolbar, &QAction::triggered, mainWindow,
341 &RenderWindow::slotUpdateDocksAndToolbarByAction);
342 connect(mainWindow->ui->actionShow_info_dock, &QAction::triggered, mainWindow,
343 &RenderWindow::slotUpdateDocksAndToolbarByAction);
344 connect(mainWindow->ui->actionShow_statistics_dock, &QAction::triggered, mainWindow,
345 &RenderWindow::slotUpdateDocksAndToolbarByAction);
346 connect(mainWindow->ui->actionShow_gamepad_dock, &QAction::triggered, mainWindow,
347 &RenderWindow::slotUpdateDocksAndToolbarByAction);
348 connect(mainWindow->ui->actionShow_queue_dock, &QAction::triggered, mainWindow,
349 &RenderWindow::slotUpdateDocksAndToolbarByAction);
350 connect(mainWindow->ui->actionShow_measurement_dock, &QAction::triggered, mainWindow,
351 &RenderWindow::slotUpdateDocksAndToolbarByAction);
352 connect(mainWindow->ui->actionSave_settings, &QAction::triggered, mainWindow,
353 &RenderWindow::slotMenuSaveSettings);
354 connect(mainWindow->ui->actionSave_settings_to_clipboard, &QAction::triggered, mainWindow,
355 &RenderWindow::slotMenuSaveSettingsToClipboard);
356 connect(mainWindow->ui->actionLoad_settings, &QAction::triggered, mainWindow,
357 &RenderWindow::slotMenuLoadSettings);
358 connect(mainWindow->ui->actionLoad_settings_from_clipboard, &QAction::triggered, mainWindow,
359 &RenderWindow::slotMenuLoadSettingsFromClipboard);
360 connect(mainWindow->ui->actionLoad_example, &QAction::triggered, mainWindow,
361 &RenderWindow::slotMenuLoadExample);
362 connect(mainWindow->ui->actionImport_settings_from_old_Mandelbulber, &QAction::triggered,
363 mainWindow, &RenderWindow::slotImportOldSettings);
364 connect(mainWindow->ui->actionImport_settings_from_Mandelbulb3d, &QAction::triggered, mainWindow,
365 &RenderWindow::slotImportMandelbulb3dSettings);
366 connect(mainWindow->ui->actionExportVoxelLayers, &QAction::triggered, mainWindow,
367 &RenderWindow::slotExportVoxelLayers);
368 connect(mainWindow->ui->actionExport_Mesh, &QAction::triggered, mainWindow,
369 &RenderWindow::slotExportMesh);
370 connect(mainWindow->ui->actionSave_as_JPG, &QAction::triggered, mainWindow,
371 &RenderWindow::slotMenuSaveImageJPEG);
372 connect(mainWindow->ui->actionSave_as_IMAGE, &QAction::triggered, mainWindow,
373 &RenderWindow::slotMenuSaveImageAll);
374 connect(mainWindow->ui->actionSave_as_PNG, &QAction::triggered, mainWindow,
375 &RenderWindow::slotMenuSaveImagePNG);
376 connect(mainWindow->ui->actionSave_as_PNG_16_bit, &QAction::triggered, mainWindow,
377 &RenderWindow::slotMenuSaveImagePNG16);
378 connect(mainWindow->ui->actionSave_as_PNG_16_bit_with_alpha_channel, &QAction::triggered,
379 mainWindow, &RenderWindow::slotMenuSaveImagePNG16Alpha);
380 #ifdef USE_EXR
381 connect(mainWindow->ui->actionSave_as_EXR, &QAction::triggered, mainWindow,
382 &RenderWindow::slotMenuSaveImageEXR);
383 #endif // USE_EXR
384
385 #ifdef USE_TIFF
386 connect(mainWindow->ui->actionSave_as_TIFF, &QAction::triggered, mainWindow,
387 &RenderWindow::slotMenuSaveImageTIFF);
388 #endif // USE_TIFF
389
390 connect(mainWindow->ui->actionAbout_Qt, &QAction::triggered, mainWindow,
391 &RenderWindow::slotMenuAboutQt);
392 connect(mainWindow->ui->actionUser_Manual, &QAction::triggered, mainWindow,
393 &RenderWindow::slotMenuAboutManual);
394 connect(mainWindow->ui->actionUser_News, &QAction::triggered, mainWindow,
395 &RenderWindow::slotMenuAboutNews);
396 connect(mainWindow->ui->actionUser_HotKeys, &QAction::triggered, mainWindow,
397 &RenderWindow::slotMenuAboutHotKeys);
398 connect(mainWindow->ui->actionAbout_Mandelbulber, &QAction::triggered, mainWindow,
399 &RenderWindow::slotMenuAboutMandelbulber);
400 connect(mainWindow->ui->actionAbout_ThirdParty, &QAction::triggered, mainWindow,
401 &RenderWindow::slotMenuAboutThirdParty);
402 connect(mainWindow->ui->actionRender_Image, &QAction::triggered, mainWindow,
403 &RenderWindow::slotMenuRenderImage);
404 connect(mainWindow->ui->actionStop_rendering, &QAction::triggered, mainWindow,
405 &RenderWindow::slotMenuStopRendering);
406 connect(mainWindow->ui->actionUndo, &QAction::triggered, mainWindow, &RenderWindow::slotMenuUndo);
407 connect(mainWindow->ui->actionRedo, &QAction::triggered, mainWindow, &RenderWindow::slotMenuRedo);
408 connect(mainWindow->ui->actionRandomizeAll, &QAction::triggered, mainWindow,
409 &RenderWindow::slotMenuRandomizeAll);
410 connect(mainWindow->ui->actionCleanSettings, &QAction::triggered, mainWindow,
411 &RenderWindow::slotCleanSettings);
412
413 connect(mainWindow->ui->actionProgramPreferences, &QAction::triggered, mainWindow,
414 &RenderWindow::slotMenuProgramPreferences);
415 connect(mainWindow->ui->actionDetach_image_from_main_window, &QAction::triggered, mainWindow,
416 &RenderWindow::slotDetachMainImage);
417
418 connect(mainWindow->ui->scrollAreaForImage, SIGNAL(resized(int, int)), mainWindow,
419 SLOT(slotResizedScrolledAreaImage(int, int)));
420 connect(mainWindow->ui->comboBox_image_preview_scale, SIGNAL(currentIndexChanged(int)),
421 mainWindow, SLOT(slotChangedComboImageScale(int)));
422
423 // rendered image widget
424 connect(
425 renderedImage, SIGNAL(mouseMoved(int, int)), mainWindow, SLOT(slotMouseMovedOnImage(int, int)));
426 connect(
427 renderedImage, &RenderedImage::singleClick, mainWindow, &RenderWindow::slotMouseClickOnImage);
428 connect(renderedImage, &RenderedImage::keyPress, mainWindow, &RenderWindow::slotKeyPressOnImage);
429 connect(
430 renderedImage, &RenderedImage::keyRelease, mainWindow, &RenderWindow::slotKeyReleaseOnImage);
431 connect(renderedImage, &RenderedImage::mouseWheelRotatedWithKey, mainWindow,
432 &RenderWindow::slotMouseWheelRotatedWithKeyOnImage);
433 connect(
434 renderedImage, &RenderedImage::mouseDragStart, mainWindow, &RenderWindow::slotMouseDragStart);
435 connect(
436 renderedImage, &RenderedImage::mouseDragFinish, mainWindow, &RenderWindow::slotMouseDragFinish);
437 connect(
438 renderedImage, &RenderedImage::mouseDragDelta, mainWindow, &RenderWindow::slotMouseDragDelta);
439
440 connect(mainWindow->ui->widgetDockRenderingEngine, SIGNAL(stateChangedConnectDetailLevel(int)),
441 mainWindow->ui->widgetImageAdjustments, SLOT(slotCheckedDetailLevelLock(int)));
442
443 // DockWidgets and Toolbar
444
445 connect(mainWindow->ui->toolBar, SIGNAL(visibilityChanged(bool)), mainWindow,
446 SLOT(slotUpdateDocksAndToolbarByView()));
447 connect(mainWindow->ui->dockWidget_animation, SIGNAL(visibilityChanged(bool)), mainWindow,
448 SLOT(slotUpdateDocksAndToolbarByView()));
449 connect(mainWindow->ui->dockWidget_info, SIGNAL(visibilityChanged(bool)), mainWindow,
450 SLOT(slotUpdateDocksAndToolbarByView()));
451 connect(mainWindow->ui->dockWidget_histogram, SIGNAL(visibilityChanged(bool)), mainWindow,
452 SLOT(slotUpdateDocksAndToolbarByView()));
453 #ifdef USE_GAMEPAD
454 connect(mainWindow->ui->dockWidget_gamepad_dock, SIGNAL(visibilityChanged(bool)), mainWindow,
455 SLOT(slotUpdateDocksAndToolbarByView()));
456 #endif
457 connect(mainWindow->ui->dockWidget_queue_dock, SIGNAL(visibilityChanged(bool)), mainWindow,
458 SLOT(slotUpdateDocksAndToolbarByView()));
459 connect(mainWindow->ui->dockWidget_measurement, SIGNAL(visibilityChanged(bool)), mainWindow,
460 SLOT(slotUpdateDocksAndToolbarByView()));
461
462 connect(mainWindow->ui->actionAdd_Settings_to_Toolbar, &QAction::triggered, mainWindow,
463 &RenderWindow::slotPresetAddToToolbar);
464 connect(mainWindow->ui->actionAdd_CustomWindowStateToMenu, &QAction::triggered, mainWindow,
465 &RenderWindow::slotCustomWindowStateAddToMenu);
466 connect(mainWindow->ui->actionRemove_Window_settings, &QAction::triggered, mainWindow,
467 &RenderWindow::slotCustomWindowRemovePopup);
468
469 //------------------------------------------------
470 mainWindow->slotUpdateDocksAndToolbarByView();
471 }
472
473 // Reading ad writing parameters from/to ui to/from parameters container
SynchronizeInterface(std::shared_ptr<cParameterContainer> par,std::shared_ptr<cFractalContainer> parFractal,qInterface::enumReadWrite mode) const474 void cInterface::SynchronizeInterface(std::shared_ptr<cParameterContainer> par,
475 std::shared_ptr<cFractalContainer> parFractal, qInterface::enumReadWrite mode) const
476 {
477 WriteLog(
478 "cInterface::SynchronizeInterface(std::shared_ptr<cParameterContainer> par, cFractalContainer "
479 "*parFractal, "
480 "enumReadWrite mode)",
481 2);
482
483 if (!gInterfaceReadyForSynchronization && mode == qInterface::read) return;
484
485 WriteLog("cInterface::SynchronizeInterface: dockWidget_effects", 3);
486 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_effects, par, mode);
487 WriteLog("cInterface::SynchronizeInterface: dockWidget_image_adjustments", 3);
488 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_image_adjustments, par, mode);
489 WriteLog("cInterface::SynchronizeInterface: dockWidget_navigation", 3);
490 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_navigation, par, mode);
491 WriteLog("cInterface::SynchronizeInterface: dockWidget_rendering_engine", 3);
492 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_rendering_engine, par, mode);
493 WriteLog("cInterface::SynchronizeInterface: dockWidget_queue_dock", 3);
494 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_queue_dock, par, mode);
495 WriteLog("cInterface::SynchronizeInterface: centralwidget", 3);
496 SynchronizeInterfaceWindow(mainWindow->ui->centralwidget, par, mode);
497 WriteLog("cInterface::SynchronizeInterface: dockWidgetContents_animation", 3);
498 SynchronizeInterfaceWindow(mainWindow->ui->dockWidgetContents_animation, par, mode);
499 WriteLog("cInterface::SynchronizeInterface: dockWidget_measurement", 3);
500 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_measurement, par, mode);
501 WriteLog("cInterface::SynchronizeInterface: materialEditor", 3);
502 SynchronizeInterfaceWindow(materialEditor, par, mode);
503
504 if (detachedWindow)
505 {
506 WriteLog("cInterface::SynchronizeInterface: materialEditor", 3);
507 SynchronizeInterfaceWindow(detachedWindow, par, mode);
508 }
509
510 mainWindow->ui->widgetDockFractal->SynchronizeInterfaceFractals(par, parFractal, mode);
511 }
512
StartRender(bool noUndo)513 void cInterface::StartRender(bool noUndo)
514 {
515 numberOfStartedRenders++;
516 if (!mainImage->IsUsed())
517 {
518 mainImage->BlockImage();
519 WriteLog("cInterface::StartRender(void) - image was free", 2);
520 }
521 else
522 {
523 WriteLog("cInterface::StartRender(void) - image was used by another instance", 2);
524 stopRequest = true;
525 while (mainImage->IsUsed())
526 {
527 gApplication->processEvents();
528 stopRequest = true;
529 }
530 mainImage->BlockImage();
531 }
532
533 gNetRender->SetAnimation(false);
534
535 repeatRequest = false;
536 progressBarAnimation->hide();
537 SynchronizeInterface(gPar, gParFractal, qInterface::read);
538
539 if (mainWindow->ui->widgetDockNavigation->AutoRefreshIsChecked())
540 {
541 // check if something was changed in settings
542 cSettings tempSettings(cSettings::formatCondensedText);
543 tempSettings.CreateText(gPar, gParFractal);
544 autoRefreshLastHash = tempSettings.GetHashCode();
545 }
546
547 if (!noUndo) gUndo->Store(gPar, gParFractal);
548
549 DisableJuliaPointMode();
550
551 cRenderJob *renderJob = new cRenderJob(
552 gPar, gParFractal, mainImage, &stopRequest, renderedImage); // deleted by deleteLater()
553
554 connect(renderJob, SIGNAL(updateProgressAndStatus(const QString &, const QString &, double)),
555 mainWindow, SLOT(slotUpdateProgressAndStatus(const QString &, const QString &, double)));
556 connect(renderJob, SIGNAL(updateStatistics(cStatistics)), mainWindow->ui->widgetDockStatistics,
557 SLOT(slotUpdateStatistics(cStatistics)));
558 connect(renderJob, &cRenderJob::fullyRendered, systemTray, &cSystemTray::showMessage);
559 connect(renderJob, SIGNAL(updateImage()), renderedImage, SLOT(update()));
560 connect(renderJob, SIGNAL(sendRenderedTilesList(QList<sRenderedTileData>)), renderedImage,
561 SLOT(showRenderedTilesList(QList<sRenderedTileData>)));
562 connect(renderJob, &cRenderJob::fullyRenderedTime, this, &cInterface::slotAutoSaveImage);
563
564 cRenderingConfiguration config;
565 config.EnableNetRender();
566
567 if (!renderJob->Init(cRenderJob::still, config))
568 {
569 mainImage->ReleaseImage();
570 cErrorMessage::showMessage(
571 QObject::tr("Cannot init renderJob, see log output for more information."),
572 cErrorMessage::errorMessage);
573 return;
574 }
575
576 // show distance in statistics table
577 double distance = GetDistanceForPoint(gPar->Get<CVector3>("camera"), gPar, gParFractal);
578 mainWindow->ui->widgetDockStatistics->UpdateDistanceToFractal(distance);
579 gKeyframeAnimation->UpdateActualCameraPosition(gPar->Get<CVector3>("camera"));
580
581 QThread *thread = new QThread; // deleted by deleteLater()
582 renderJob->moveToThread(thread);
583 QObject::connect(thread, SIGNAL(started()), renderJob, SLOT(slotExecute()));
584 QObject::connect(renderJob, SIGNAL(finished()), thread, SLOT(quit()));
585 QObject::connect(renderJob, SIGNAL(finished()), renderJob, SLOT(deleteLater()));
586 QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
587
588 thread->setObjectName("RenderJob");
589 thread->start();
590 numberOfStartedRenders--;
591 }
592
MoveCamera(QString buttonName,bool synchronizeAndRender)593 void cInterface::MoveCamera(QString buttonName, bool synchronizeAndRender)
594 {
595 using namespace cameraMovementEnums;
596
597 WriteLog("cInterface::MoveCamera(QString buttonName): button: " + buttonName, 2);
598
599 // get data from interface
600 if (synchronizeAndRender) SynchronizeInterface(gPar, gParFractal, qInterface::read);
601 CVector3 camera = gPar->Get<CVector3>("camera");
602 CVector3 target = gPar->Get<CVector3>("target");
603 CVector3 topVector = gPar->Get<CVector3>("camera_top");
604 cCameraTarget cameraTarget(camera, target, topVector);
605
606 bool legacyCoordinateSystem = gPar->Get<bool>("legacy_coordinate_system");
607 double reverse = legacyCoordinateSystem ? -1.0 : 1.0;
608
609 // get direction vector
610 CVector3 direction;
611 if (buttonName == "bu_move_left")
612 direction = cameraTarget.GetRightVector() * (-1.0);
613 else if (buttonName == "bu_move_right")
614 direction = cameraTarget.GetRightVector() * (1.0);
615 else if (buttonName == "bu_move_up")
616 direction = cameraTarget.GetTopVector() * (1.0) * reverse;
617 else if (buttonName == "bu_move_down")
618 direction = cameraTarget.GetTopVector() * (-1.0) * reverse;
619 else if (buttonName == "bu_move_forward")
620 direction = cameraTarget.GetForwardVector() * (1.0);
621 else if (buttonName == "bu_move_backward")
622 direction = cameraTarget.GetForwardVector() * (-1.0);
623
624 enumCameraMovementStepMode stepMode =
625 enumCameraMovementStepMode(gPar->Get<int>("camera_absolute_distance_mode"));
626 enumCameraMovementMode movementMode =
627 enumCameraMovementMode(gPar->Get<int>("camera_movement_mode"));
628
629 // movement step
630 double step;
631 if (stepMode == absolute)
632 {
633 step = gPar->Get<double>("camera_movement_step");
634 }
635 else
636 {
637 double relativeStep = gPar->Get<double>("camera_movement_step");
638
639 CVector3 point;
640 if (movementMode == moveTarget)
641 point = target;
642 else
643 point = camera;
644
645 double distance = GetDistanceForPoint(point, gPar, gParFractal);
646
647 step = relativeStep * distance;
648 }
649
650 // movement
651 if (movementMode == moveCamera)
652 camera += direction * step;
653 else if (movementMode == moveTarget)
654 target += direction * step;
655 else if (movementMode == fixedDistance)
656 {
657 camera += direction * step;
658 target += direction * step;
659 }
660
661 // put data to interface
662 gPar->Set("camera", camera);
663 gPar->Set("target", target);
664
665 // recalculation of camera-target
666 cCameraTarget::enumRotationMode rollMode =
667 cCameraTarget::enumRotationMode(gPar->Get<int>("camera_straight_rotation"));
668 if (movementMode == moveCamera)
669 cameraTarget.SetCamera(camera, rollMode);
670 else if (movementMode == moveTarget)
671 cameraTarget.SetTarget(target, rollMode);
672 else if (movementMode == fixedDistance)
673 cameraTarget.SetCameraTargetTop(camera, target, topVector);
674
675 topVector = cameraTarget.GetTopVector();
676 gPar->Set("camera_top", topVector);
677 CVector3 rotation = cameraTarget.GetRotation();
678 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
679 double dist = cameraTarget.GetDistance();
680 gPar->Set("camera_distance_to_target", dist);
681
682 if (synchronizeAndRender) SynchronizeInterface(gPar, gParFractal, qInterface::write);
683 if (synchronizeAndRender) StartRender();
684 }
685
CameraOrTargetEdited() const686 void cInterface::CameraOrTargetEdited() const
687 {
688 WriteLog("cInterface::CameraOrTargetEdited(void)", 2);
689
690 // get data from interface before synchronization
691 CVector3 camera = gPar->Get<CVector3>("camera");
692 CVector3 target = gPar->Get<CVector3>("target");
693 CVector3 topVector = gPar->Get<CVector3>("camera_top");
694 cCameraTarget cameraTarget(camera, target, topVector);
695
696 SynchronizeInterface(gPar, gParFractal, qInterface::read);
697 camera = gPar->Get<CVector3>("camera");
698 target = gPar->Get<CVector3>("target");
699
700 // recalculation of camera-target
701 cCameraTarget::enumRotationMode rollMode =
702 cCameraTarget::enumRotationMode(gPar->Get<int>("camera_straight_rotation"));
703 cameraTarget.SetCamera(camera, rollMode);
704 cameraTarget.SetTarget(target, rollMode);
705
706 topVector = cameraTarget.GetTopVector();
707 gPar->Set("camera_top", topVector);
708 CVector3 rotation = cameraTarget.GetRotation();
709 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
710 double dist = cameraTarget.GetDistance();
711 gPar->Set("camera_distance_to_target", dist);
712
713 SynchronizeInterface(gPar, gParFractal, qInterface::write);
714 }
715
RotateCamera(QString buttonName,bool synchronizeAndRender)716 void cInterface::RotateCamera(QString buttonName, bool synchronizeAndRender)
717 {
718 using namespace cameraMovementEnums;
719
720 WriteLog("cInterface::RotateCamera(QString buttonName): button: " + buttonName, 2);
721
722 // get data from interface
723 if (synchronizeAndRender) SynchronizeInterface(gPar, gParFractal, qInterface::read);
724 CVector3 camera = gPar->Get<CVector3>("camera");
725 CVector3 target = gPar->Get<CVector3>("target");
726 CVector3 topVector = gPar->Get<CVector3>("camera_top");
727 cCameraTarget cameraTarget(camera, target, topVector);
728 double distance = cameraTarget.GetDistance();
729
730 enumCameraRotationMode rotationMode =
731 enumCameraRotationMode(gPar->Get<int>("camera_rotation_mode"));
732 cCameraTarget::enumRotationMode rollMode =
733 cCameraTarget::enumRotationMode(gPar->Get<int>("camera_straight_rotation"));
734
735 bool legacyCoordinateSystem = gPar->Get<bool>("legacy_coordinate_system");
736 double reverse = legacyCoordinateSystem ? -1.0 : 1.0;
737
738 CVector3 rotationAxis;
739 if (rollMode == cCameraTarget::constantRoll)
740 {
741 if (buttonName == "bu_rotate_left")
742 rotationAxis = CVector3(0.0, 0.0, 1.0);
743 else if (buttonName == "bu_rotate_right")
744 rotationAxis = CVector3(0.0, 0.0, -1.0);
745 else if (buttonName == "bu_rotate_up")
746 {
747 rotationAxis = CVector3(1.0 * reverse, 0.0, 0.0);
748 rotationAxis = rotationAxis.RotateAroundVectorByAngle(
749 CVector3(0.0, 0.0, 1.0), cameraTarget.GetRotation().x);
750 }
751 else if (buttonName == "bu_rotate_down")
752 {
753 rotationAxis = CVector3(-1.0 * reverse, 0.0, 0.0);
754 rotationAxis = rotationAxis.RotateAroundVectorByAngle(
755 CVector3(0.0, 0.0, 1.0), cameraTarget.GetRotation().x);
756 }
757 else if (buttonName == "bu_rotate_roll_left")
758 rotationAxis = cameraTarget.GetForwardVector() * (-1.0) * reverse;
759 else if (buttonName == "bu_rotate_roll_right")
760 rotationAxis = cameraTarget.GetForwardVector() * (1.0) * reverse;
761 }
762 else
763 {
764 if (buttonName == "bu_rotate_left")
765 rotationAxis = cameraTarget.GetTopVector() * (1.0);
766 else if (buttonName == "bu_rotate_right")
767 rotationAxis = cameraTarget.GetTopVector() * (-1.0);
768 else if (buttonName == "bu_rotate_up")
769 rotationAxis = cameraTarget.GetRightVector() * (1.0) * reverse;
770 else if (buttonName == "bu_rotate_down")
771 rotationAxis = cameraTarget.GetRightVector() * (-1.0) * reverse;
772 else if (buttonName == "bu_rotate_roll_left")
773 rotationAxis = cameraTarget.GetForwardVector() * (-1.0) * reverse;
774 else if (buttonName == "bu_rotate_roll_right")
775 rotationAxis = cameraTarget.GetForwardVector() * (1.0) * reverse;
776 }
777
778 if (rotationMode == rotateAroundTarget) rotationAxis *= -1.0;
779
780 // rotation of vectors
781 CVector3 forwardVector = cameraTarget.GetForwardVector();
782 double rotationStep = gPar->Get<double>("camera_rotation_step") * (M_PI / 180.0);
783 forwardVector = forwardVector.RotateAroundVectorByAngle(rotationAxis, rotationStep);
784 topVector = topVector.RotateAroundVectorByAngle(rotationAxis, rotationStep);
785
786 if (rotationMode == rotateCamera)
787 {
788 target = camera + forwardVector * distance;
789 }
790 else
791 {
792 camera = target - forwardVector * distance;
793 }
794
795 // recalculation of camera-target
796 cameraTarget.SetCameraTargetTop(camera, target, topVector);
797
798 gPar->Set("camera", camera);
799 gPar->Set("target", target);
800 gPar->Set("camera_top", topVector);
801 CVector3 rotation = cameraTarget.GetRotation();
802 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
803 double dist = cameraTarget.GetDistance();
804 gPar->Set("camera_distance_to_target", dist);
805
806 if (synchronizeAndRender) SynchronizeInterface(gPar, gParFractal, qInterface::write);
807 if (synchronizeAndRender) StartRender();
808 }
809
RotationEdited() const810 void cInterface::RotationEdited() const
811 {
812 using namespace cameraMovementEnums;
813
814 WriteLog("cInterface::RotationEdited(void)", 2);
815 // get data from interface before synchronization
816 SynchronizeInterface(gPar, gParFractal, qInterface::read);
817 CVector3 camera = gPar->Get<CVector3>("camera");
818 CVector3 target = gPar->Get<CVector3>("target");
819 CVector3 topVector = gPar->Get<CVector3>("camera_top");
820 cCameraTarget cameraTarget(camera, target, topVector);
821 double distance = cameraTarget.GetDistance();
822 CVector3 rotation = gPar->Get<CVector3>("camera_rotation") * (M_PI / 180.0);
823
824 enumCameraRotationMode rotationMode =
825 enumCameraRotationMode(gPar->Get<int>("camera_rotation_mode"));
826
827 CVector3 forwardVector(0.0, 1.0, 0.0);
828 forwardVector = forwardVector.RotateAroundVectorByAngle(CVector3(0.0, 1.0, 0.0), rotation.z);
829 forwardVector = forwardVector.RotateAroundVectorByAngle(CVector3(1.0, 0.0, 0.0), rotation.y);
830 forwardVector = forwardVector.RotateAroundVectorByAngle(CVector3(0.0, 0.0, 1.0), rotation.x);
831
832 if (rotationMode == rotateCamera)
833 {
834 target = camera + forwardVector * distance;
835 }
836 else
837 {
838 camera = target - forwardVector * distance;
839 }
840 cameraTarget.SetCameraTargetRotation(camera, target, rotation.z);
841 gPar->Set("camera", camera);
842 gPar->Set("target", target);
843 gPar->Set("camera_top", cameraTarget.GetTopVector());
844 SynchronizeInterface(gPar, gParFractal, qInterface::write);
845 }
846
CameraDistanceEdited() const847 void cInterface::CameraDistanceEdited() const
848 {
849 using namespace cameraMovementEnums;
850
851 WriteLog("cInterface::CameraDistanceEdited()", 2);
852
853 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_navigation, gPar, qInterface::read);
854 CVector3 camera = gPar->Get<CVector3>("camera");
855 CVector3 target = gPar->Get<CVector3>("target");
856 CVector3 topVector = gPar->Get<CVector3>("camera_top");
857 cCameraTarget cameraTarget(camera, target, topVector);
858 CVector3 forwardVector = cameraTarget.GetForwardVector();
859
860 double distance = gPar->Get<double>("camera_distance_to_target");
861
862 enumCameraMovementMode movementMode =
863 enumCameraMovementMode(gPar->Get<int>("camera_movement_mode"));
864 if (movementMode == moveTarget)
865 {
866 target = camera + forwardVector * distance;
867 }
868 else
869 {
870 camera = target - forwardVector * distance;
871 }
872
873 cameraTarget.SetCameraTargetTop(camera, target, topVector);
874 gPar->Set("camera", camera);
875 gPar->Set("target", target);
876 gPar->Set("camera_top", cameraTarget.GetTopVector());
877 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_navigation, gPar, qInterface::write);
878 }
879
IFSDefaultsDodecahedron(std::shared_ptr<cParameterContainer> parFractal) const880 void cInterface::IFSDefaultsDodecahedron(std::shared_ptr<cParameterContainer> parFractal) const
881 {
882 double phi = (1 + sqrt(5.0)) / 2.0;
883 parFractal->Set("IFS_scale", phi * phi);
884 parFractal->Set("IFS_direction_0", CVector3(phi * phi, 1.0, -phi));
885 parFractal->Set("IFS_direction_1", CVector3(-phi, phi * phi, 1.0));
886 parFractal->Set("IFS_direction_2", CVector3(1.0, -phi, phi * phi));
887 parFractal->Set("IFS_enabled_0", true);
888 parFractal->Set("IFS_enabled_1", true);
889 parFractal->Set("IFS_enabled_2", true);
890 parFractal->Set("IFS_offset", CVector3(1.0, 1.0, 1.0));
891 parFractal->Set("IFS_abs_x", true);
892 parFractal->Set("IFS_abs_y", true);
893 parFractal->Set("IFS_abs_z", true);
894 parFractal->Set("IFS_menger_sponge_mode", false);
895 }
896
IFSDefaultsIcosahedron(std::shared_ptr<cParameterContainer> parFractal) const897 void cInterface::IFSDefaultsIcosahedron(std::shared_ptr<cParameterContainer> parFractal) const
898 {
899 double phi = (1 + sqrt(5.0)) / 2.0;
900 parFractal->Set("IFS_scale", 2.0);
901 parFractal->Set("IFS_direction_3", CVector3(-phi * phi, 1.0, phi));
902 parFractal->Set("IFS_direction_4", CVector3(phi, -phi * phi, 1.0));
903 parFractal->Set("IFS_enabled_3", true);
904 parFractal->Set("IFS_enabled_4", true);
905 parFractal->Set("IFS_offset", CVector3(1.0, 0.0, phi));
906 parFractal->Set("IFS_abs_x", true);
907 parFractal->Set("IFS_abs_y", true);
908 parFractal->Set("IFS_abs_z", true);
909 parFractal->Set("IFS_menger_sponge_mode", false);
910 }
911
IFSDefaultsOctahedron(std::shared_ptr<cParameterContainer> parFractal)912 void cInterface::IFSDefaultsOctahedron(std::shared_ptr<cParameterContainer> parFractal)
913 {
914 parFractal->Set("IFS_scale", 2.0);
915 parFractal->Set("IFS_direction_5", CVector3(1.0, -1.0, 0));
916 parFractal->Set("IFS_direction_6", CVector3(1.0, 0.0, -1.0));
917 parFractal->Set("IFS_direction_7", CVector3(0.0, 1.0, -1.0));
918 parFractal->Set("IFS_enabled_5", true);
919 parFractal->Set("IFS_enabled_6", true);
920 parFractal->Set("IFS_enabled_7", true);
921 parFractal->Set("IFS_offset", CVector3(1.0, 0.0, 0.0));
922 parFractal->Set("IFS_abs_x", true);
923 parFractal->Set("IFS_abs_y", true);
924 parFractal->Set("IFS_abs_z", true);
925 parFractal->Set("IFS_menger_sponge_mode", false);
926 }
927
IFSDefaultsMengerSponge(std::shared_ptr<cParameterContainer> parFractal)928 void cInterface::IFSDefaultsMengerSponge(std::shared_ptr<cParameterContainer> parFractal)
929 {
930 parFractal->Set("IFS_scale", 3.0);
931 parFractal->Set("IFS_direction_5", CVector3(1.0, -1.0, 0));
932 parFractal->Set("IFS_direction_6", CVector3(1.0, 0.0, -1.0));
933 parFractal->Set("IFS_direction_7", CVector3(0.0, 1.0, -1.0));
934 parFractal->Set("IFS_enabled_5", true);
935 parFractal->Set("IFS_enabled_6", true);
936 parFractal->Set("IFS_enabled_7", true);
937 parFractal->Set("IFS_offset", CVector3(1.0, 1.0, 1.0));
938 parFractal->Set("IFS_abs_x", true);
939 parFractal->Set("IFS_abs_y", true);
940 parFractal->Set("IFS_abs_z", true);
941 parFractal->Set("IFS_menger_sponge_mode", true);
942 }
943
IFSDefaultsReset(std::shared_ptr<cParameterContainer> parFractal)944 void cInterface::IFSDefaultsReset(std::shared_ptr<cParameterContainer> parFractal)
945 {
946 for (int i = 0; i < 9; i++)
947 {
948 parFractal->Set("IFS_direction", i, CVector3(1.0, 0.0, 0.0));
949 parFractal->Set("IFS_rotations", i, CVector3(0.0, 0.0, 0.0));
950 parFractal->Set("IFS_distance", i, 0.0);
951 parFractal->Set("IFS_enabled", i, false);
952 parFractal->Set("IFS_intensity", i, 1.0);
953 }
954 parFractal->Set("IFS_offset", CVector3(1.0, 0.0, 0.0));
955 parFractal->Set("IFS_abs_x", false);
956 parFractal->Set("IFS_abs_y", false);
957 parFractal->Set("IFS_abs_z", false);
958 parFractal->Set("IFS_menger_sponge_mode", false);
959 parFractal->Set("IFS_scale", 2.0);
960 parFractal->Set("IFS_rotation", CVector3(0.0, 0.0, 0.0));
961 parFractal->Set("IFS_rotation_enabled", false);
962 parFractal->Set("IFS_edge", CVector3(0.0, 0.0, 0.0));
963 parFractal->Set("IFS_edge_enabled", false);
964 }
965
RefreshMainImage()966 void cInterface::RefreshMainImage()
967 {
968 if (!mainImage->IsUsed())
969 {
970 SynchronizeInterface(gPar, gParFractal, qInterface::read);
971 sImageAdjustments imageAdjustments;
972 imageAdjustments.brightness = gPar->Get<float>("brightness");
973 imageAdjustments.contrast = gPar->Get<float>("contrast");
974 imageAdjustments.imageGamma = gPar->Get<float>("gamma");
975 imageAdjustments.saturation = gPar->Get<float>("saturation");
976 imageAdjustments.hdrEnabled = gPar->Get<bool>("hdr");
977
978 mainImage->SetImageParameters(imageAdjustments);
979 mainImage->CompileImage();
980
981 mainImage->ConvertTo8bitChar();
982 mainImage->UpdatePreview();
983 if (mainImage->GetImageWidget()) mainImage->GetImageWidget()->update();
984 }
985 else
986 {
987 cErrorMessage::showMessage(
988 QObject::tr("You cannot apply changes during rendering. You will do this after rendering."),
989 cErrorMessage::warningMessage, mainWindow);
990 }
991 }
992
RefreshPostEffects()993 void cInterface::RefreshPostEffects()
994 {
995 if (!mainImage->IsUsed())
996 {
997 mainImage->NullPostEffect();
998
999 RefreshMainImage();
1000
1001 // replace image size parameters in case if user changed image size just before image update
1002 gPar->Set("image_width", int(mainImage->GetWidth()));
1003 gPar->Set("image_height", int(mainImage->GetHeight()));
1004
1005 stopRequest = false;
1006 if (gPar->Get<bool>("ambient_occlusion_enabled")
1007 && gPar->Get<int>("ambient_occlusion_mode") == params::AOModeScreenSpace)
1008 {
1009 if (gPar->Get<bool>("opencl_enabled")
1010 && cOpenClEngineRenderFractal::enumClRenderEngineMode(gPar->Get<int>("opencl_mode"))
1011 != cOpenClEngineRenderFractal::clRenderEngineTypeNone)
1012 {
1013 #ifdef USE_OPENCL
1014 sParamRender params(gPar);
1015 gOpenCl->openClEngineRenderSSAO->Lock();
1016 cRegion<int> region(0, 0, mainImage->GetWidth(), mainImage->GetHeight());
1017 gOpenCl->openClEngineRenderSSAO->SetParameters(¶ms, region);
1018 if (gOpenCl->openClEngineRenderSSAO->LoadSourcesAndCompile(gPar))
1019 {
1020 gOpenCl->openClEngineRenderSSAO->CreateKernel4Program(gPar);
1021 size_t neededMem = gOpenCl->openClEngineRenderSSAO->CalcNeededMemory();
1022 WriteLogDouble("OpenCl render SSAO - needed mem:", neededMem / 1048576.0, 2);
1023 if (neededMem / 1048576 < size_t(gPar->Get<int>("opencl_memory_limit")))
1024 {
1025 gOpenCl->openClEngineRenderSSAO->PreAllocateBuffers(gPar);
1026 gOpenCl->openClEngineRenderSSAO->CreateCommandQueue();
1027 gOpenCl->openClEngineRenderSSAO->Render(mainImage, &stopRequest);
1028 }
1029 else
1030 {
1031 cErrorMessage::showMessage(
1032 QObject::tr("Not enough free memory in OpenCL device to render SSAO effect!"),
1033 cErrorMessage::errorMessage, mainWindow);
1034 }
1035 }
1036 gOpenCl->openClEngineRenderSSAO->ReleaseMemory();
1037 gOpenCl->openClEngineRenderSSAO->Unlock();
1038 #endif
1039 }
1040 else
1041 {
1042 std::shared_ptr<sParamRender> params(new sParamRender(gPar));
1043 std::shared_ptr<sRenderData> data(new sRenderData());
1044 data->stopRequest = &stopRequest;
1045 data->screenRegion = cRegion<int>(0, 0, mainImage->GetWidth(), mainImage->GetHeight());
1046 cRenderSSAO rendererSSAO(params, data, mainImage);
1047 QObject::connect(&rendererSSAO,
1048 SIGNAL(updateProgressAndStatus(const QString &, const QString &, double)), mainWindow,
1049 SLOT(slotUpdateProgressAndStatus(const QString &, const QString &, double)));
1050 connect(&rendererSSAO, SIGNAL(updateImage()), renderedImage, SLOT(update()));
1051
1052 rendererSSAO.RenderSSAO();
1053
1054 mainImage->CompileImage();
1055 mainImage->ConvertTo8bitChar();
1056 mainImage->UpdatePreview();
1057 if (mainImage->GetImageWidget()) mainImage->GetImageWidget()->update();
1058 }
1059 }
1060
1061 if (gPar->Get<bool>("DOF_enabled"))
1062 {
1063 if (gPar->Get<bool>("opencl_enabled")
1064 && cOpenClEngineRenderFractal::enumClRenderEngineMode(gPar->Get<int>("opencl_mode"))
1065 != cOpenClEngineRenderFractal::clRenderEngineTypeNone)
1066 {
1067 #ifdef USE_OPENCL
1068 cRegion<int> screenRegion(0, 0, mainImage->GetWidth(), mainImage->GetHeight());
1069 sParamRender params(gPar);
1070 gOpenCl->openclEngineRenderDOF->RenderDOF(
1071 ¶ms, gPar, mainImage, &stopRequest, screenRegion);
1072 #endif
1073 }
1074 else
1075 {
1076 sParamRender params(gPar);
1077 // cRenderingConfiguration config;
1078 cPostRenderingDOF dof(mainImage);
1079 connect(&dof, SIGNAL(updateProgressAndStatus(const QString &, const QString &, double)),
1080 mainWindow, SLOT(slotUpdateProgressAndStatus(const QString &, const QString &, double)));
1081 connect(&dof, SIGNAL(updateImage()), renderedImage, SLOT(update()));
1082 cRegion<int> screenRegion(0, 0, mainImage->GetWidth(), mainImage->GetHeight());
1083 dof.Render(screenRegion,
1084 params.DOFRadius * (mainImage->GetWidth() + mainImage->GetHeight()) / 2000.0,
1085 params.DOFFocus, params.DOFNumberOfPasses, params.DOFBlurOpacity, params.DOFMaxRadius,
1086 &stopRequest);
1087 }
1088 }
1089
1090 if (gPar->Get<bool>("opencl_enabled")
1091 && cOpenClEngineRenderFractal::enumClRenderEngineMode(gPar->Get<int>("opencl_mode"))
1092 != cOpenClEngineRenderFractal::clRenderEngineTypeNone)
1093 {
1094 #ifdef USE_OPENCL
1095
1096 connect(gOpenCl->openclEngineRenderPostFilter,
1097 SIGNAL(updateProgressAndStatus(const QString &, const QString &, double)), mainWindow,
1098 SLOT(slotUpdateProgressAndStatus(const QString &, const QString &, double)));
1099
1100 for (int i = cOpenClEngineRenderPostFilter::hdrBlur;
1101 i <= cOpenClEngineRenderPostFilter::chromaticAberration; i++)
1102 {
1103
1104 bool skip = false;
1105 switch (cOpenClEngineRenderPostFilter::enumPostEffectType(i))
1106 {
1107 case cOpenClEngineRenderPostFilter::hdrBlur:
1108 {
1109 if (!gPar->Get<bool>("hdr_blur_enabled")) skip = true;
1110 break;
1111 }
1112 case cOpenClEngineRenderPostFilter::chromaticAberration:
1113 {
1114 if (!gPar->Get<bool>("post_chromatic_aberration_enabled")) skip = true;
1115 break;
1116 }
1117 }
1118
1119 if (skip) continue;
1120
1121 sParamRender params(gPar);
1122 gOpenCl->openclEngineRenderPostFilter->Lock();
1123 cRegion<int> region(0, 0, mainImage->GetWidth(), mainImage->GetHeight());
1124 gOpenCl->openclEngineRenderPostFilter->SetParameters(
1125 ¶ms, region, cOpenClEngineRenderPostFilter::enumPostEffectType(i));
1126 if (gOpenCl->openclEngineRenderPostFilter->LoadSourcesAndCompile(gPar))
1127 {
1128 gOpenCl->openclEngineRenderPostFilter->CreateKernel4Program(gPar);
1129 size_t neededMem = gOpenCl->openclEngineRenderPostFilter->CalcNeededMemory();
1130 WriteLogDouble("OpenCl render Post Filter - needed mem:", neededMem / 1048576.0, 2);
1131 if (neededMem / 1048576 < size_t(gPar->Get<int>("opencl_memory_limit")))
1132 {
1133 gOpenCl->openclEngineRenderPostFilter->PreAllocateBuffers(gPar);
1134 gOpenCl->openclEngineRenderPostFilter->CreateCommandQueue();
1135 gOpenCl->openclEngineRenderPostFilter->Render(mainImage, &stopRequest);
1136 }
1137 else
1138 {
1139 cErrorMessage::showMessage(
1140 QObject::tr("Not enough free memory in OpenCL device to render SSAO effect!"),
1141 cErrorMessage::errorMessage, mainWindow);
1142 }
1143 }
1144 gOpenCl->openclEngineRenderPostFilter->ReleaseMemory();
1145 gOpenCl->openclEngineRenderPostFilter->Unlock();
1146 }
1147 #endif
1148 }
1149 else
1150 {
1151 if (gPar->Get<bool>("hdr_blur_enabled"))
1152 {
1153 std::unique_ptr<cPostEffectHdrBlur> hdrBlur(new cPostEffectHdrBlur(mainImage));
1154 double blurRadius = gPar->Get<double>("hdr_blur_radius");
1155 double blurIntensity = gPar->Get<double>("hdr_blur_intensity");
1156 hdrBlur->SetParameters(blurRadius, blurIntensity);
1157 QObject::connect(hdrBlur.get(),
1158 SIGNAL(updateProgressAndStatus(const QString &, const QString &, double)), mainWindow,
1159 SLOT(slotUpdateProgressAndStatus(const QString &, const QString &, double)));
1160 hdrBlur->Render(&stopRequest);
1161 }
1162 }
1163
1164 mainImage->CompileImage();
1165
1166 mainImage->ConvertTo8bitChar();
1167 mainImage->UpdatePreview();
1168 if (mainImage->GetImageWidget()) mainImage->GetImageWidget()->update();
1169 }
1170 else
1171 {
1172 cErrorMessage::showMessage(
1173 QObject::tr("You cannot apply changes during rendering. You will do this after rendering."),
1174 cErrorMessage::warningMessage, mainWindow);
1175 }
1176 }
1177
AutoFog() const1178 void cInterface::AutoFog() const
1179 {
1180 SynchronizeInterface(gPar, gParFractal, qInterface::read);
1181 double distance = GetDistanceForPoint(gPar->Get<CVector3>("camera"), gPar, gParFractal);
1182 double fogDensity = 0.5;
1183 double fogDistanceFactor = distance;
1184 double fogColour1Distance = distance * 0.5;
1185 double fogColour2Distance = distance;
1186 gPar->Set("volumetric_fog_distance_factor", fogDistanceFactor);
1187 gPar->Set("volumetric_fog_colour_1_distance", fogColour1Distance);
1188 gPar->Set("volumetric_fog_colour_2_distance", fogColour2Distance);
1189 gPar->Set("volumetric_fog_density", fogDensity);
1190 SynchronizeInterface(gPar, gParFractal, qInterface::write);
1191 }
1192
GetDistanceForPoint(CVector3 point,std::shared_ptr<cParameterContainer> par,std::shared_ptr<cFractalContainer> parFractal)1193 double cInterface::GetDistanceForPoint(CVector3 point, std::shared_ptr<cParameterContainer> par,
1194 std::shared_ptr<cFractalContainer> parFractal)
1195 {
1196 std::shared_ptr<sParamRender> params(new sParamRender(par));
1197 std::shared_ptr<cNineFractals> fractals(new cNineFractals(parFractal, par));
1198 sDistanceIn in(point, 0, false);
1199 sDistanceOut out;
1200
1201 bool openClEnabled = false;
1202 #ifdef USE_OPENCL
1203 openClEnabled = par->Get<bool>("opencl_enabled") && parFractal->isUsedCustomFormula();
1204
1205 if (openClEnabled)
1206 {
1207 gOpenCl->openClEngineRenderFractal->Lock();
1208 gOpenCl->openClEngineRenderFractal->SetDistanceMode();
1209 gOpenCl->openClEngineRenderFractal->SetParameters(
1210 par, parFractal, params, fractals, nullptr, false);
1211 if (gOpenCl->openClEngineRenderFractal->LoadSourcesAndCompile(par))
1212 {
1213 gOpenCl->openClEngineRenderFractal->CreateKernel4Program(par);
1214 gOpenCl->openClEngineRenderFractal->PreAllocateBuffers(par);
1215 gOpenCl->openClEngineRenderFractal->CreateCommandQueue();
1216 }
1217 else
1218 {
1219 gOpenCl->openClEngineRenderFractal->ReleaseMemory();
1220 gOpenCl->openClEngineRenderFractal->Unlock();
1221 return 0.0;
1222 }
1223 }
1224 #endif
1225
1226 double dist;
1227 if (openClEnabled)
1228 {
1229 #ifdef USE_OPENCL
1230 dist = gOpenCl->openClEngineRenderFractal->CalculateDistance(point);
1231 #endif
1232 }
1233 else
1234 {
1235 dist = CalculateDistance(*params, *fractals, in, &out);
1236 }
1237
1238 #ifdef USE_OPENCL
1239 if (openClEnabled)
1240 {
1241 gOpenCl->openClEngineRenderFractal->ReleaseMemory();
1242 gOpenCl->openClEngineRenderFractal->Unlock();
1243 }
1244 #endif
1245
1246 return dist;
1247 }
1248
GetDistanceForPoint(CVector3 point) const1249 double cInterface::GetDistanceForPoint(CVector3 point) const
1250 {
1251 SynchronizeInterface(gPar, gParFractal, qInterface::read);
1252 double distance = GetDistanceForPoint(point, gPar, gParFractal);
1253 return distance;
1254 }
1255
SetByMouse(CVector2<double> screenPoint,Qt::MouseButton button,const QList<QVariant> & mode)1256 void cInterface::SetByMouse(
1257 CVector2<double> screenPoint, Qt::MouseButton button, const QList<QVariant> &mode)
1258 {
1259 using namespace cameraMovementEnums;
1260
1261 WriteLog(
1262 QString("MoveCameraByMouse(CVector2<double> screenPoint, Qt::MouseButton button): button: ")
1263 + button,
1264 2);
1265 // get data from interface
1266
1267 RenderedImage::enumClickMode clickMode = RenderedImage::enumClickMode(mode.at(0).toInt());
1268
1269 SynchronizeInterface(gPar, gParFractal, qInterface::read);
1270 CVector3 camera = gPar->Get<CVector3>("camera");
1271 CVector3 target = gPar->Get<CVector3>("target");
1272 CVector3 topVector = gPar->Get<CVector3>("camera_top");
1273 cCameraTarget cameraTarget(camera, target, topVector);
1274
1275 enumCameraMovementStepMode stepMode =
1276 enumCameraMovementStepMode(gPar->Get<int>("camera_absolute_distance_mode"));
1277 enumCameraMovementMode movementMode =
1278 enumCameraMovementMode(gPar->Get<int>("camera_movement_mode"));
1279 params::enumPerspectiveType perspType =
1280 params::enumPerspectiveType(gPar->Get<int>("perspective_type"));
1281 cCameraTarget::enumRotationMode rollMode =
1282 cCameraTarget::enumRotationMode(gPar->Get<int>("camera_straight_rotation"));
1283 double movementStep = gPar->Get<double>("camera_movement_step");
1284 double fov = CalcFOV(gPar->Get<double>("fov"), perspType);
1285 bool legacyCoordinateSystem = gPar->Get<bool>("legacy_coordinate_system");
1286 double reverse = legacyCoordinateSystem ? -1.0 : 1.0;
1287
1288 double sweetSpotHAngle = gPar->Get<double>("sweet_spot_horizontal_angle") / 180.0 * M_PI;
1289 double sweetSpotVAngle = gPar->Get<double>("sweet_spot_vertical_angle") / 180.0 * M_PI;
1290
1291 CVector2<double> imagePoint;
1292 imagePoint = screenPoint / mainImage->GetPreviewScale();
1293
1294 int width = mainImage->GetWidth();
1295 int height = mainImage->GetHeight();
1296
1297 if (imagePoint.x >= 0 && imagePoint.x < mainImage->GetWidth() && imagePoint.y >= 0
1298 && imagePoint.y < mainImage->GetHeight())
1299 {
1300 double depth = mainImage->GetPixelZBuffer(imagePoint.x, imagePoint.y);
1301 if (depth < 1e10)
1302 {
1303 CVector3 viewVector;
1304 double aspectRatio = double(width) / height;
1305
1306 if (perspType == params::perspEquirectangular) aspectRatio = 2.0;
1307
1308 double wheelDistance = 1.0;
1309 if (clickMode == RenderedImage::clickMoveCamera)
1310 {
1311
1312 if (mode.length() > 1) // if mouse wheel delta is available
1313 {
1314 int wheelDelta = mode.at(1).toInt();
1315 wheelDistance = 0.001 * fabs(wheelDelta);
1316 }
1317 }
1318
1319 CVector3 angles = cameraTarget.GetRotation();
1320 CRotationMatrix mRot;
1321 mRot.SetRotation(angles);
1322 mRot.RotateZ(-sweetSpotHAngle);
1323 mRot.RotateX(sweetSpotVAngle);
1324
1325 CVector2<double> normalizedPoint;
1326 normalizedPoint.x = (imagePoint.x / width - 0.5) * aspectRatio;
1327 normalizedPoint.y = (imagePoint.y / height - 0.5) * (-1.0) * reverse;
1328
1329 normalizedPoint *= wheelDistance;
1330
1331 viewVector = CalculateViewVector(normalizedPoint, fov, perspType, mRot);
1332
1333 CVector3 point = camera + viewVector * depth;
1334
1335 switch (clickMode)
1336 {
1337 case RenderedImage::clickMoveCamera:
1338 {
1339 double distance = (camera - point).Length();
1340
1341 double moveDistance = (stepMode == absolute) ? movementStep : distance * movementStep;
1342 moveDistance *= wheelDistance;
1343
1344 if (stepMode == relative)
1345 {
1346 if (moveDistance > depth * 0.99) moveDistance = depth * 0.99;
1347 }
1348
1349 if (button == Qt::RightButton)
1350 {
1351 moveDistance *= -1.0;
1352 }
1353
1354 switch (movementMode)
1355 {
1356 case moveTarget: target = point; break;
1357
1358 case moveCamera: camera += viewVector * moveDistance; break;
1359
1360 case fixedDistance:
1361 camera += viewVector * moveDistance;
1362 target = point;
1363 break;
1364 }
1365
1366 // recalculation of camera-target
1367 if (movementMode == moveCamera)
1368 cameraTarget.SetCamera(camera, rollMode);
1369 else if (movementMode == moveTarget)
1370 cameraTarget.SetTarget(target, rollMode);
1371 else if (movementMode == fixedDistance)
1372 cameraTarget.SetCameraTargetTop(camera, target, topVector);
1373
1374 if (rollMode == cCameraTarget::constantRoll)
1375 {
1376 cameraTarget.SetCameraTargetRotation(camera, target, angles.z);
1377 }
1378
1379 gPar->Set("camera", camera);
1380 gPar->Set("target", target);
1381
1382 topVector = cameraTarget.GetTopVector();
1383 gPar->Set("camera_top", topVector);
1384 CVector3 rotation = cameraTarget.GetRotation();
1385 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
1386 double dist = cameraTarget.GetDistance();
1387 gPar->Set("camera_distance_to_target", dist);
1388
1389 SynchronizeInterface(gPar, gParFractal, qInterface::write);
1390 renderedImage->setNewZ(depth - moveDistance);
1391
1392 StartRender();
1393
1394 break;
1395 }
1396 case RenderedImage::clickFogVisibility:
1397 {
1398 double fogDepth = depth;
1399 gPar->Set("basic_fog_visibility", fogDepth);
1400 mainWindow->ui->widgetEffects->SynchronizeInterfaceBasicFogEnabled(gPar);
1401 StartRender();
1402 break;
1403 }
1404 case RenderedImage::clickDOFFocus:
1405 {
1406 DisablePeriodicRefresh();
1407 double DOF = depth;
1408 gPar->Set("DOF_focus", DOF);
1409 mainWindow->ui->widgetEffects->SynchronizeInterfaceDOFEnabled(gPar);
1410 gUndo->Store(gPar, gParFractal);
1411 RefreshPostEffects();
1412 ReEnablePeriodicRefresh();
1413 break;
1414 }
1415 case RenderedImage::clickPlaceLight:
1416 {
1417 int lightIndex = mode.at(1).toInt();
1418 double frontDist = gPar->Get<double>("aux_light_manual_placement_dist");
1419 bool placeBehind = gPar->Get<bool>("aux_light_place_behind");
1420 double distanceLimit = gPar->Get<double>("view_distance_max");
1421 bool relativePosition = gPar->Get<bool>(cLight::Name("relative_position", lightIndex));
1422
1423 CVector3 pointCorrected;
1424
1425 if (!placeBehind)
1426 {
1427 pointCorrected = point - viewVector * frontDist;
1428 }
1429 else
1430 {
1431 frontDist = traceBehindFractal(gPar, gParFractal, frontDist, viewVector, depth,
1432 1.0 / mainImage->GetHeight(), distanceLimit)
1433 * (-1.0);
1434 pointCorrected = point - viewVector * frontDist;
1435 }
1436
1437 double estDistance = GetDistanceForPoint(pointCorrected, gPar, gParFractal);
1438 double intensity = estDistance * estDistance;
1439
1440 if (relativePosition)
1441 {
1442 // without rotation
1443 CVector3 viewVectorTemp =
1444 CalculateViewVector(normalizedPoint, fov, perspType, CRotationMatrix());
1445
1446 CVector3 point2 = viewVectorTemp * (depth - frontDist);
1447 pointCorrected = CVector3(point2.x, point2.z, point2.y);
1448 }
1449
1450 gPar->Set(cLight::Name("position", lightIndex), pointCorrected);
1451 gPar->Set(cLight::Name("intensity", lightIndex), intensity);
1452 mainWindow->ui->widgetEffects->SynchronizeInterfaceLights(gPar);
1453 StartRender();
1454 break;
1455 }
1456 case RenderedImage::clickGetJuliaConstant:
1457 {
1458 gPar->Set("julia_c", point);
1459 mainWindow->ui->widgetDockFractal->EnableJuliaMode();
1460 mainWindow->ui->widgetDockFractal->SynchronizeInterfaceJulia();
1461
1462 // StartRender();
1463 break;
1464 }
1465 case RenderedImage::clickPlacePrimitive:
1466 {
1467 QString parameterName = mode.at(3).toString() + "_position";
1468 gPar->Set(parameterName, point);
1469 mainWindow->ui->widgetDockFractal->SynchronizeInterfacePrimitives();
1470 break;
1471 }
1472 case RenderedImage::clickDoNothing:
1473 // nothing
1474 break;
1475 case RenderedImage::clickFlightSpeedControl:
1476 // nothing
1477 break;
1478 case RenderedImage::clickPlaceRandomLightCenter:
1479 {
1480 double distanceCameraToCenter = CVector3(camera - point).Length();
1481 gPar->Set("random_lights_distribution_center", point);
1482 gPar->Set("random_lights_distribution_radius", 0.5 * distanceCameraToCenter);
1483 gPar->Set("random_lights_max_distance_from_fractal", 0.1 * distanceCameraToCenter);
1484 mainWindow->ui->widgetEffects->SynchronizeInterfaceRandomLights(gPar);
1485 StartRender();
1486 break;
1487 }
1488 case RenderedImage::clickGetPoint:
1489 {
1490 DisablePeriodicRefresh();
1491 SynchronizeInterface(gPar, gParFractal, qInterface::read);
1492 CVector3 oldPoint = gPar->Get<CVector3>("meas_point");
1493 double distanceFromLast = (point - oldPoint).Length();
1494 double distanceFromCamera = (point - camera).Length();
1495 CVector3 midPoint = 0.5 * (point + oldPoint);
1496 gPar->Set("meas_point", point);
1497 gPar->Set("meas_midpoint", midPoint);
1498 gPar->Set("meas_distance_from_last", distanceFromLast);
1499 gPar->Set("meas_distance_from_camera", distanceFromCamera);
1500 SynchronizeInterfaceWindow(
1501 mainWindow->ui->dockWidget_measurement, gPar, qInterface::write);
1502 if (!mainWindow->ui->actionShow_measurement_dock->isChecked())
1503 {
1504 mainWindow->ui->actionShow_measurement_dock->setChecked(true);
1505 mainWindow->slotUpdateDocksAndToolbarByAction();
1506 }
1507 ReEnablePeriodicRefresh();
1508 break;
1509 }
1510 case RenderedImage::clickWrapLimitsAroundObject:
1511 {
1512 double distanceCameraToCenter = CVector3(camera - point).Length();
1513 CVector3 distanceV111_100 = CVector3(1.0 * distanceCameraToCenter,
1514 1.0 * distanceCameraToCenter, 1.0 * distanceCameraToCenter);
1515 CVector3 limitMin = point - distanceV111_100;
1516 CVector3 limitMax = point + distanceV111_100;
1517 // try to find object close limits in the bounding box defined by point +- 100% distance
1518 // to view vector
1519 SetBoundingBoxAsLimits(limitMin, limitMax);
1520 break;
1521 }
1522 }
1523 }
1524 }
1525 }
1526
MouseDragStart(CVector2<double> screenPoint,Qt::MouseButtons button,const QList<QVariant> & mode)1527 void cInterface::MouseDragStart(
1528 CVector2<double> screenPoint, Qt::MouseButtons button, const QList<QVariant> &mode)
1529 {
1530 mouseDragData = sMouseDragInitData();
1531
1532 RenderedImage::enumClickMode clickMode = RenderedImage::enumClickMode(mode.at(0).toInt());
1533
1534 int lightIndex = -1;
1535 if (clickMode == RenderedImage::clickPlaceLight)
1536 {
1537 lightIndex = mode.at(1).toInt();
1538 mouseDragData.lightDrag = true;
1539
1540 mouseDragData.lightStartPosition = gPar->Get<CVector3>(cLight::Name("position", lightIndex));
1541 }
1542 else
1543 {
1544 mouseDragData.cameraDrag = true;
1545 }
1546
1547 SynchronizeInterface(gPar, gParFractal, qInterface::read);
1548 CVector3 camera = gPar->Get<CVector3>("camera");
1549 CVector3 target = gPar->Get<CVector3>("target");
1550 CVector3 topVector = gPar->Get<CVector3>("camera_top");
1551 cCameraTarget cameraTarget(camera, target, topVector);
1552
1553 params::enumPerspectiveType perspType =
1554 params::enumPerspectiveType(gPar->Get<int>("perspective_type"));
1555 double sweetSpotHAngle = gPar->Get<double>("sweet_spot_horizontal_angle") / 180.0 * M_PI;
1556 double sweetSpotVAngle = gPar->Get<double>("sweet_spot_vertical_angle") / 180.0 * M_PI;
1557 double fov = CalcFOV(gPar->Get<double>("fov"), perspType);
1558 bool legacyCoordinateSystem = gPar->Get<bool>("legacy_coordinate_system");
1559 double reverse = legacyCoordinateSystem ? -1.0 : 1.0;
1560
1561 CVector2<double> imagePoint;
1562 imagePoint = screenPoint / mainImage->GetPreviewScale();
1563
1564 int width = mainImage->GetWidth();
1565 int height = mainImage->GetHeight();
1566
1567 if (imagePoint.x >= 0 && imagePoint.x < mainImage->GetWidth() && imagePoint.y >= 0
1568 && imagePoint.y < mainImage->GetHeight())
1569 {
1570 double depth = mainImage->GetPixelZBuffer(imagePoint.x, imagePoint.y);
1571 if (depth < 1e10 || clickMode == RenderedImage::clickPlaceLight)
1572 {
1573 CVector3 viewVector;
1574 double aspectRatio = double(width) / height;
1575
1576 if (perspType == params::perspEquirectangular) aspectRatio = 2.0;
1577
1578 CVector3 angles = cameraTarget.GetRotation();
1579 CRotationMatrix mRot;
1580 mRot.SetRotation(angles);
1581 mRot.RotateZ(-sweetSpotHAngle);
1582 mRot.RotateX(sweetSpotVAngle);
1583
1584 CVector2<double> normalizedPoint;
1585 normalizedPoint.x = (imagePoint.x / width - 0.5) * aspectRatio;
1586 normalizedPoint.y = (imagePoint.y / height - 0.5) * (-1.0) * reverse;
1587
1588 viewVector = CalculateViewVector(normalizedPoint, fov, perspType, mRot);
1589
1590 CVector3 point = camera + viewVector * depth;
1591
1592 mouseDragData.startCamera = camera;
1593 mouseDragData.startTarget = target;
1594 mouseDragData.startTopVector = topVector;
1595 mouseDragData.startIndicatedPoint = point;
1596 mouseDragData.button = button;
1597 mouseDragData.startScreenPoint = screenPoint;
1598 mouseDragData.startNormalizedPoint = normalizedPoint;
1599 mouseDragData.startZ = depth;
1600 mouseDragData.lastRefreshTime.restart();
1601 mouseDragData.lastStartRenderingTime = 0;
1602 mouseDragData.lightIndex = lightIndex;
1603
1604 if (clickMode == RenderedImage::clickMoveCamera
1605 || clickMode == RenderedImage::clickPlaceLight)
1606 {
1607 mouseDragData.draggingStarted = true;
1608 }
1609 }
1610 }
1611 }
1612
MouseDragFinish()1613 void cInterface::MouseDragFinish()
1614 {
1615 mouseDragData.draggingStarted = false;
1616 }
1617
MouseDragCameraLeftButton(const sMouseDragTempData & dragTempData)1618 void cInterface::MouseDragCameraLeftButton(const sMouseDragTempData &dragTempData)
1619 {
1620 CVector3 camera = mouseDragData.startCamera;
1621 cCameraTarget cameraTarget(camera, mouseDragData.startTarget, mouseDragData.startTopVector);
1622
1623 CVector3 angles = cameraTarget.GetRotation();
1624 CRotationMatrix mRot;
1625 mRot.SetRotation(angles);
1626 mRot.RotateZ(-dragTempData.sweetSpotHAngle);
1627 mRot.RotateX(dragTempData.sweetSpotVAngle);
1628
1629 CVector2<double> normalizedPoint;
1630 normalizedPoint.x =
1631 (dragTempData.imagePoint.x / dragTempData.width - 0.5) * dragTempData.aspectRatio;
1632 normalizedPoint.y =
1633 (dragTempData.imagePoint.y / dragTempData.height - 0.5) * (-1.0) * dragTempData.reverse;
1634
1635 CVector3 viewVector =
1636 CalculateViewVector(normalizedPoint, dragTempData.fov, dragTempData.perspType, mRot);
1637
1638 CVector3 point = camera + viewVector * mouseDragData.startZ;
1639 CVector3 deltaPoint = point - mouseDragData.startIndicatedPoint;
1640 CVector3 pointCamera = camera - point;
1641 pointCamera.Normalize();
1642
1643 CVector3 relativeVector;
1644 relativeVector.z = pointCamera.Dot(deltaPoint);
1645 relativeVector.x = pointCamera.Cross(cameraTarget.GetTopVector()).Dot(deltaPoint);
1646 relativeVector.y = pointCamera.Cross(cameraTarget.GetRightVector()).Dot(deltaPoint);
1647
1648 double ratio = (camera - mouseDragData.startTarget).Length() / (camera - point).Length();
1649 if (dragTempData.perspType == params::perspThreePoint)
1650 {
1651 ratio /= -pointCamera.Dot(cameraTarget.GetForwardVector());
1652 }
1653 relativeVector *= ratio;
1654
1655 CVector3 newTarget = mouseDragData.startTarget;
1656 newTarget -= relativeVector.x * cameraTarget.GetRightVector();
1657 newTarget += relativeVector.y * cameraTarget.GetTopVector();
1658 newTarget += relativeVector.z * cameraTarget.GetForwardVector();
1659
1660 cameraTarget.SetTarget(newTarget, dragTempData.rollMode);
1661
1662 gPar->Set("camera", camera);
1663 gPar->Set("target", newTarget);
1664 CVector3 topVector = cameraTarget.GetTopVector();
1665 gPar->Set("camera_top", topVector);
1666 CVector3 rotation = cameraTarget.GetRotation();
1667 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
1668 double dist = cameraTarget.GetDistance();
1669 gPar->Set("camera_distance_to_target", dist);
1670 }
1671
MouseDragCaneraRightButton(int dx,int dy,const sMouseDragTempData & dragTempData)1672 void cInterface::MouseDragCaneraRightButton(int dx, int dy, const sMouseDragTempData &dragTempData)
1673 {
1674 cCameraTarget cameraTarget(
1675 mouseDragData.startCamera, mouseDragData.startTarget, mouseDragData.startTopVector);
1676
1677 CVector3 shiftedCamera = mouseDragData.startCamera - mouseDragData.startIndicatedPoint;
1678 CVector3 shiftedTarget = mouseDragData.startTarget - mouseDragData.startIndicatedPoint;
1679 shiftedCamera = shiftedCamera.RotateAroundVectorByAngle(
1680 cameraTarget.GetTopVector(), (double)(dx) / mainImage->GetPreviewWidth() * M_PI_2);
1681 shiftedTarget = shiftedTarget.RotateAroundVectorByAngle(
1682 cameraTarget.GetTopVector(), (double)(dx) / mainImage->GetPreviewWidth() * M_PI_2);
1683
1684 CVector3 newCamera = shiftedCamera + mouseDragData.startIndicatedPoint;
1685 CVector3 newTarget = shiftedTarget + mouseDragData.startIndicatedPoint;
1686 cameraTarget.SetCamera(newCamera, dragTempData.rollMode);
1687 cameraTarget.SetTarget(newTarget, dragTempData.rollMode);
1688
1689 shiftedCamera = shiftedCamera.RotateAroundVectorByAngle(
1690 cameraTarget.GetRightVector(), (double)(dy) / mainImage->GetPreviewHeight() * M_PI_2);
1691 shiftedTarget = shiftedTarget.RotateAroundVectorByAngle(
1692 cameraTarget.GetRightVector(), (double)(dy) / mainImage->GetPreviewHeight() * M_PI_2);
1693
1694 newCamera = shiftedCamera + mouseDragData.startIndicatedPoint;
1695 newTarget = shiftedTarget + mouseDragData.startIndicatedPoint;
1696
1697 cameraTarget.SetCamera(newCamera, dragTempData.rollMode);
1698 cameraTarget.SetTarget(newTarget, dragTempData.rollMode);
1699
1700 gPar->Set("camera", cameraTarget.GetCamera());
1701 gPar->Set("target", cameraTarget.GetTarget());
1702 CVector3 topVector = cameraTarget.GetTopVector();
1703 gPar->Set("camera_top", topVector);
1704 CVector3 rotation = cameraTarget.GetRotation();
1705 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
1706 double dist = cameraTarget.GetDistance();
1707 gPar->Set("camera_distance_to_target", dist);
1708 }
1709
MouseDragCameraMiddleButton(int dx)1710 void cInterface::MouseDragCameraMiddleButton(int dx)
1711 {
1712 double angle = -(double)(dx) / mainImage->GetPreviewHeight() * M_PI_2;
1713 cCameraTarget cameraTarget(
1714 mouseDragData.startCamera, mouseDragData.startTarget, mouseDragData.startTopVector);
1715 CVector3 newTopVector =
1716 mouseDragData.startTopVector.RotateAroundVectorByAngle(cameraTarget.GetForwardVector(), angle);
1717 cameraTarget.SetCameraTargetTop(
1718 mouseDragData.startCamera, mouseDragData.startTarget, newTopVector);
1719 gPar->Set("camera_top", newTopVector);
1720 CVector3 rotation = cameraTarget.GetRotation();
1721 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
1722 }
1723
MouseDragLeftRightButtons(const sMouseDragTempData & dragTempData)1724 void cInterface::MouseDragLeftRightButtons(const sMouseDragTempData &dragTempData)
1725 {
1726 CVector3 camera = mouseDragData.startCamera;
1727 cCameraTarget cameraTarget(camera, mouseDragData.startTarget, mouseDragData.startTopVector);
1728
1729 CVector3 angles = cameraTarget.GetRotation();
1730 CRotationMatrix mRot;
1731 mRot.SetRotation(angles);
1732 mRot.RotateZ(-dragTempData.sweetSpotHAngle);
1733 mRot.RotateX(dragTempData.sweetSpotVAngle);
1734
1735 CVector2<double> normalizedPoint;
1736 normalizedPoint.x =
1737 (dragTempData.imagePoint.x / dragTempData.width - 0.5) * dragTempData.aspectRatio;
1738 normalizedPoint.y =
1739 (dragTempData.imagePoint.y / dragTempData.height - 0.5) * (-1.0) * dragTempData.reverse;
1740
1741 CVector3 viewVector =
1742 CalculateViewVector(normalizedPoint, dragTempData.fov, dragTempData.perspType, mRot);
1743
1744 CVector3 point = camera + viewVector * mouseDragData.startZ;
1745 CVector3 deltaPoint = point - mouseDragData.startIndicatedPoint;
1746 CVector3 newTarget = mouseDragData.startTarget + deltaPoint;
1747 CVector3 newCamera = mouseDragData.startCamera + deltaPoint;
1748
1749 cameraTarget.SetCameraTargetTop(newCamera, newTarget, cameraTarget.GetTopVector());
1750
1751 gPar->Set("camera", newCamera);
1752 gPar->Set("target", newTarget);
1753 CVector3 topVector = cameraTarget.GetTopVector();
1754 gPar->Set("camera_top", topVector);
1755 CVector3 rotation = cameraTarget.GetRotation();
1756 gPar->Set("camera_rotation", rotation * (180.0 / M_PI));
1757 double dist = cameraTarget.GetDistance();
1758 gPar->Set("camera_distance_to_target", dist);
1759 }
1760
LightDragLeftButton(const sMouseDragTempData & dragTempData,int dx,int dy)1761 void cInterface::LightDragLeftButton(const sMouseDragTempData &dragTempData, int dx, int dy)
1762 {
1763 bool relativePosition =
1764 gPar->Get<bool>(cLight::Name("relative_position", mouseDragData.lightIndex));
1765
1766 cCameraTarget cameraTarget(
1767 mouseDragData.startCamera, mouseDragData.startTarget, mouseDragData.startTopVector);
1768
1769 CVector3 lightPosition = mouseDragData.lightStartPosition;
1770
1771 if (relativePosition)
1772 {
1773 CVector3 deltaPositionRotated = cameraTarget.GetForwardVector() * lightPosition.z
1774 + cameraTarget.GetTopVector() * lightPosition.y
1775 + cameraTarget.GetRightVector() * lightPosition.x;
1776 lightPosition = mouseDragData.startCamera + deltaPositionRotated;
1777 }
1778
1779 CRotationMatrix mRotInv;
1780 CVector3 rotation = cameraTarget.GetRotation();
1781 mRotInv.RotateY(-rotation.z);
1782 mRotInv.RotateX(-rotation.y);
1783 mRotInv.RotateZ(-rotation.x);
1784
1785 CVector3 lightScreenPosition =
1786 InvProjection3D(lightPosition, mouseDragData.startCamera, mRotInv, dragTempData.perspType,
1787 dragTempData.fov, mainImage->GetPreviewWidth(), mainImage->GetPreviewHeight());
1788 CVector3 newLightScreenPosition = lightScreenPosition + CVector3(dx, dy, 0.0);
1789
1790 CRotationMatrix mRot;
1791 mRot.SetRotation(rotation);
1792
1793 CVector2<double> normalizedPoint;
1794 normalizedPoint.x =
1795 (newLightScreenPosition.x / mainImage->GetPreviewWidth() - 0.5) * dragTempData.aspectRatio;
1796 normalizedPoint.y = (newLightScreenPosition.y / mainImage->GetPreviewHeight() - 0.5) * (-1.0)
1797 * dragTempData.reverse;
1798
1799 CVector3 viewVector =
1800 CalculateViewVector(normalizedPoint, dragTempData.fov, dragTempData.perspType, mRot);
1801
1802 CVector3 newLightPosition;
1803 if (relativePosition)
1804 {
1805 // without rotation
1806 CVector3 viewVectorTemp = CalculateViewVector(
1807 normalizedPoint, dragTempData.fov, dragTempData.perspType, CRotationMatrix());
1808 CVector3 point2 = viewVectorTemp * lightScreenPosition.z;
1809 newLightPosition = CVector3(point2.x, point2.z, point2.y);
1810 }
1811 else
1812 {
1813 newLightPosition = mouseDragData.startCamera + viewVector * lightScreenPosition.z;
1814 }
1815
1816 gPar->Set(cLight::Name("position", mouseDragData.lightIndex), newLightPosition);
1817 }
1818
MouseDragDelta(int dx,int dy)1819 void cInterface::MouseDragDelta(int dx, int dy)
1820 {
1821 if (mouseDragData.draggingStarted)
1822 {
1823 if (numberOfStartedRenders > 1) stopRequest = true;
1824
1825 if (mouseDragData.lastRefreshTime.elapsed()
1826 > gPar->Get<double>("auto_refresh_period") * 1000 + mouseDragData.lastStartRenderingTime
1827 && numberOfStartedRenders < 2)
1828 {
1829 sMouseDragTempData dragTempData;
1830
1831 mouseDragData.lastRefreshTime.restart();
1832 dragTempData.perspType = params::enumPerspectiveType(gPar->Get<int>("perspective_type"));
1833 dragTempData.sweetSpotHAngle =
1834 gPar->Get<double>("sweet_spot_horizontal_angle") / 180.0 * M_PI;
1835 dragTempData.sweetSpotVAngle = gPar->Get<double>("sweet_spot_vertical_angle") / 180.0 * M_PI;
1836 dragTempData.legacyCoordinateSystem = gPar->Get<bool>("legacy_coordinate_system");
1837 dragTempData.reverse = dragTempData.legacyCoordinateSystem ? -1.0 : 1.0;
1838 dragTempData.fov = CalcFOV(gPar->Get<double>("fov"), dragTempData.perspType);
1839 dragTempData.rollMode =
1840 cCameraTarget::enumRotationMode(gPar->Get<int>("camera_straight_rotation"));
1841
1842 dragTempData.newScreenPoint = CVector2<double>(
1843 mouseDragData.startScreenPoint.x - dx, mouseDragData.startScreenPoint.y - dy);
1844 dragTempData.imagePoint = dragTempData.newScreenPoint / mainImage->GetPreviewScale();
1845
1846 dragTempData.width = mainImage->GetWidth();
1847 dragTempData.height = mainImage->GetHeight();
1848 dragTempData.aspectRatio = double(dragTempData.width) / dragTempData.height;
1849 if (dragTempData.perspType == params::perspEquirectangular) dragTempData.aspectRatio = 2.0;
1850
1851 if (mouseDragData.cameraDrag)
1852 {
1853 switch (mouseDragData.button)
1854 {
1855 case Qt::LeftButton:
1856 {
1857 MouseDragCameraLeftButton(dragTempData);
1858 break;
1859 }
1860 case Qt::RightButton:
1861 {
1862 MouseDragCaneraRightButton(dx, dy, dragTempData);
1863 break;
1864 }
1865 case Qt::MiddleButton:
1866 {
1867 MouseDragCameraMiddleButton(dx);
1868 break;
1869 }
1870
1871 case (Qt::LeftButton | Qt::RightButton):
1872 {
1873 MouseDragLeftRightButtons(dragTempData);
1874 break;
1875 }
1876
1877 default: break;
1878 }
1879
1880 QElapsedTimer timerStartRender;
1881 timerStartRender.start();
1882 SynchronizeInterface(gPar, gParFractal, qInterface::write);
1883 StartRender();
1884 mouseDragData.lastStartRenderingTime = timerStartRender.elapsed();
1885 }
1886 else if (mouseDragData.lightDrag)
1887 {
1888 switch (mouseDragData.button)
1889 {
1890 case Qt::LeftButton:
1891 {
1892 LightDragLeftButton(dragTempData, dx, dy);
1893 break;
1894 }
1895 default:
1896 {
1897 break;
1898 }
1899 }
1900 QElapsedTimer timerStartRender;
1901 timerStartRender.start();
1902 SynchronizeInterface(gPar, gParFractal, qInterface::write);
1903 renderedImage->update();
1904 mouseDragData.lastStartRenderingTime = timerStartRender.elapsed();
1905 }
1906 }
1907 }
1908 }
1909
MoveLightByWheel(double deltaWheel)1910 void cInterface::MoveLightByWheel(double deltaWheel)
1911 {
1912 double deltaLog = exp(deltaWheel * 0.0001);
1913
1914 CVector3 lightPosition =
1915 gPar->Get<CVector3>(cLight::Name("position", renderedImage->GetCurrentLightIndex()));
1916
1917 bool relativePosition =
1918 gPar->Get<bool>(cLight::Name("relative_position", renderedImage->GetCurrentLightIndex()));
1919
1920 CVector3 newLightPosition;
1921
1922 if (relativePosition)
1923 {
1924 newLightPosition = lightPosition * deltaLog;
1925 }
1926 else
1927 {
1928 CVector3 cameraPosition = gPar->Get<CVector3>("camera");
1929 CVector3 lightVector = lightPosition - cameraPosition;
1930 CVector3 newLightVector = lightVector * deltaLog;
1931 newLightPosition = cameraPosition + newLightVector;
1932 }
1933
1934 gPar->Set(cLight::Name("position", renderedImage->GetCurrentLightIndex()), newLightPosition);
1935 SynchronizeInterface(gPar, gParFractal, qInterface::write);
1936 renderedImage->update();
1937 }
1938
MovementStepModeChanged(int mode) const1939 void cInterface::MovementStepModeChanged(int mode) const
1940 {
1941 using namespace cameraMovementEnums;
1942
1943 SynchronizeInterface(gPar, gParFractal, qInterface::read);
1944 enumCameraMovementStepMode stepMode = enumCameraMovementStepMode(mode);
1945 double distance = GetDistanceForPoint(gPar->Get<CVector3>("camera"), gPar, gParFractal);
1946 double oldStep = gPar->Get<double>("camera_movement_step");
1947 double newStep;
1948 if (stepMode == absolute)
1949 {
1950 newStep = oldStep * distance;
1951 if (distance > 1.0 && newStep > distance * 0.5) newStep = distance * 0.5;
1952 }
1953 else
1954 {
1955 newStep = oldStep / distance;
1956 if (distance > 1.0 && newStep > 0.5) newStep = 0.5;
1957 }
1958 gPar->Set("camera_movement_step", newStep);
1959 SynchronizeInterfaceWindow(mainWindow->ui->dockWidget_navigation, gPar, qInterface::write);
1960 }
1961
Undo()1962 void cInterface::Undo()
1963 {
1964 bool refreshFrames = false;
1965 bool refreshKeyframes = false;
1966 DisablePeriodicRefresh();
1967 gInterfaceReadyForSynchronization = false;
1968 if (gUndo->Undo(gPar, gParFractal, gAnimFrames, gKeyframes, &refreshFrames, &refreshKeyframes))
1969 {
1970 RebuildPrimitives(gPar);
1971 materialListModel->Regenerate();
1972 mainWindow->ui->widgetEffects->RegenerateLights();
1973 gInterfaceReadyForSynchronization = false;
1974 SynchronizeInterface(gPar, gParFractal, qInterface::write);
1975 if (refreshFrames) gFlightAnimation->RefreshTable();
1976 if (refreshKeyframes) gKeyframeAnimation->RefreshTable();
1977 StartRender(true);
1978 }
1979 gInterfaceReadyForSynchronization = true;
1980 ReEnablePeriodicRefresh();
1981 }
1982
Redo()1983 void cInterface::Redo()
1984 {
1985 bool refreshFrames = false;
1986 bool refreshKeyframes = false;
1987 DisablePeriodicRefresh();
1988 gInterfaceReadyForSynchronization = false;
1989 if (gUndo->Redo(gPar, gParFractal, gAnimFrames, gKeyframes, &refreshFrames, &refreshKeyframes))
1990 {
1991 RebuildPrimitives(gPar);
1992 materialListModel->Regenerate();
1993 mainWindow->ui->widgetEffects->RegenerateLights();
1994 gInterfaceReadyForSynchronization = false;
1995 SynchronizeInterface(gPar, gParFractal, qInterface::write);
1996 if (refreshFrames) gFlightAnimation->RefreshTable();
1997 if (refreshKeyframes) gKeyframeAnimation->RefreshTable();
1998 StartRender(true);
1999 }
2000 gInterfaceReadyForSynchronization = true;
2001 ReEnablePeriodicRefresh();
2002 }
2003
ResetView()2004 void cInterface::ResetView()
2005 {
2006 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2007
2008 CVector3 camera = gPar->Get<CVector3>("camera");
2009 CVector3 target = gPar->Get<CVector3>("target");
2010 CVector3 topVector = gPar->Get<CVector3>("camera_top");
2011 cCameraTarget cameraTarget(camera, target, topVector);
2012 CVector3 forwardVector = cameraTarget.GetForwardVector();
2013 params::enumPerspectiveType perspType =
2014 params::enumPerspectiveType(gPar->Get<int>("perspective_type"));
2015 double fov = CalcFOV(gPar->Get<double>("fov"), perspType);
2016 double DEFactor = gPar->Get<double>("DE_factor");
2017
2018 std::shared_ptr<cParameterContainer> parTemp(new cParameterContainer);
2019 *parTemp = *gPar;
2020 parTemp->Set("limits_enabled", false);
2021 parTemp->Set("interior_mode", false);
2022
2023 QStringList listOfParameters = parTemp->GetListOfParameters();
2024 for (const QString ¶meterName : listOfParameters)
2025 {
2026 if (parameterName.contains("primitive_plane") && parameterName.contains("enabled"))
2027 {
2028 parTemp->Set(parameterName, false);
2029 }
2030
2031 if (parameterName.contains("primitive_water") && parameterName.contains("enabled"))
2032 {
2033 parTemp->Set(parameterName, false);
2034 }
2035 }
2036
2037 // calculate size of the fractal in random directions
2038 double maxDist = 0.0;
2039
2040 std::shared_ptr<sParamRender> params(new sParamRender(parTemp));
2041 std::shared_ptr<cNineFractals> fractals(new cNineFractals(gParFractal, parTemp));
2042
2043 bool openClEnabled = false;
2044 #ifdef USE_OPENCL
2045 openClEnabled = parTemp->Get<bool>("opencl_enabled") && gParFractal->isUsedCustomFormula();
2046
2047 if (openClEnabled)
2048 {
2049 gOpenCl->openClEngineRenderFractal->Lock();
2050 gOpenCl->openClEngineRenderFractal->SetDistanceMode();
2051 gOpenCl->openClEngineRenderFractal->SetParameters(
2052 parTemp, gParFractal, params, fractals, nullptr, false);
2053 if (gOpenCl->openClEngineRenderFractal->LoadSourcesAndCompile(parTemp))
2054 {
2055 gOpenCl->openClEngineRenderFractal->CreateKernel4Program(parTemp);
2056 gOpenCl->openClEngineRenderFractal->PreAllocateBuffers(parTemp);
2057 gOpenCl->openClEngineRenderFractal->CreateCommandQueue();
2058 }
2059 else
2060 {
2061 gOpenCl->openClEngineRenderFractal->ReleaseMemory();
2062 gOpenCl->openClEngineRenderFractal->Unlock();
2063 return;
2064 }
2065 }
2066 #endif
2067
2068 for (int i = 0; i < 100; i++)
2069 {
2070 cProgressText::ProgressStatusText(QObject::tr("Resetting view"),
2071 QObject::tr("Fractal size calculation"), i / 50.0, cProgressText::progress_IMAGE);
2072 CVector3 direction(
2073 Random(1000) / 500.0 - 1.0, Random(1000) / 500.0 - 1.0, Random(1000) / 500.0 - 1.0);
2074 direction.Normalize();
2075 double distStep;
2076 double scan;
2077
2078 for (scan = 100.0; scan > 0; scan -= distStep)
2079 {
2080 CVector3 point = direction * scan;
2081 sDistanceIn in(point, 0, false);
2082 sDistanceOut out;
2083
2084 double dist;
2085 if (openClEnabled)
2086 {
2087 #ifdef USE_OPENCL
2088 dist = gOpenCl->openClEngineRenderFractal->CalculateDistance(point);
2089 #endif
2090 }
2091 else
2092 {
2093 dist = CalculateDistance(*params, *fractals, in, &out);
2094 }
2095 if (dist < 0.1)
2096 {
2097 break;
2098 }
2099 distStep = dist * DEFactor * 0.5;
2100 if (distStep > 1.0) distStep = 1.0;
2101 // qDebug() << "i" << i << "scan" << scan << "direction" << direction.Debug();
2102 }
2103 if (scan > maxDist) maxDist = scan;
2104 }
2105 cProgressText::ProgressStatusText(
2106 QObject::tr("Resetting view"), QObject::tr("Done"), 1.0, cProgressText::progress_IMAGE);
2107
2108 double newCameraDist;
2109
2110 #ifdef USE_OPENCL
2111 if (openClEnabled)
2112 {
2113 gOpenCl->openClEngineRenderFractal->ReleaseMemory();
2114 gOpenCl->openClEngineRenderFractal->Unlock();
2115 }
2116 #endif
2117
2118 if (perspType == params::perspThreePoint)
2119 {
2120 newCameraDist = maxDist / fov * 2.0 * sqrt(2);
2121 }
2122 else if (perspType == params::perspEquirectangular)
2123 {
2124 newCameraDist = maxDist / fov * 4.0;
2125 }
2126 else
2127 {
2128 newCameraDist = maxDist / fov * 2.0;
2129 }
2130
2131 if (newCameraDist < 0.1) newCameraDist = 0.1;
2132
2133 gPar->Set("target", CVector3(0.0, 0.0, 0.0));
2134 CVector3 newCamera = forwardVector * newCameraDist * (-1.0);
2135 gPar->Set("camera", newCamera);
2136 gPar->Set("camera_distance_to_target", newCameraDist);
2137 gPar->Set("view_distance_max", (newCameraDist + maxDist) * 2.0);
2138 SynchronizeInterface(gPar, gParFractal, qInterface::write);
2139 StartRender();
2140 }
2141
BoundingBoxMove(char dimension,double moveLower,double moveUpper)2142 void cInterface::BoundingBoxMove(char dimension, double moveLower, double moveUpper)
2143 {
2144 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2145 CVector3 limitMin = gPar->Get<CVector3>("limit_min");
2146 CVector3 limitMax = gPar->Get<CVector3>("limit_max");
2147 CVector3 limitDifference = limitMax - limitMin;
2148 switch (dimension)
2149 {
2150 case 'x':
2151 limitMin.x -= moveLower * limitDifference.x;
2152 limitMax.x += moveUpper * limitDifference.x;
2153 break;
2154 case 'y':
2155 limitMin.y -= moveLower * limitDifference.y;
2156 limitMax.y += moveUpper * limitDifference.y;
2157 break;
2158 case 'z':
2159 limitMin.z -= moveLower * limitDifference.z;
2160 limitMax.z += moveUpper * limitDifference.z;
2161 break;
2162 default: break;
2163 }
2164 gPar->Set("limit_min", limitMin);
2165 gPar->Set("limit_max", limitMax);
2166 SynchronizeInterface(gPar, gParFractal, qInterface::write);
2167 }
2168
SetBoundingBoxAsLimitsTotal()2169 void cInterface::SetBoundingBoxAsLimitsTotal()
2170 {
2171 double outerBounding = gPar->Get<double>("limit_outer_bounding");
2172 CVector3 outerBoundingMin(-outerBounding, -outerBounding, -outerBounding);
2173 CVector3 outerBoundingMax(outerBounding, outerBounding, outerBounding);
2174 SetBoundingBoxAsLimits(outerBoundingMin, outerBoundingMax);
2175 }
2176
SetBoundingBoxAsLimits(CVector3 outerBoundingMin,CVector3 outerBoundingMax)2177 void cInterface::SetBoundingBoxAsLimits(CVector3 outerBoundingMin, CVector3 outerBoundingMax)
2178 {
2179 CVector3 boundingCenter = (outerBoundingMin + outerBoundingMax) / 2;
2180
2181 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2182
2183 auto parTemp = std::make_shared<cParameterContainer>();
2184 *parTemp = *gPar;
2185
2186 parTemp->Set("limits_enabled", false);
2187 parTemp->Set("interior_mode", false);
2188
2189 std::shared_ptr<sParamRender> params(new sParamRender(parTemp));
2190 std::shared_ptr<cNineFractals> fractals(new cNineFractals(gParFractal, parTemp));
2191
2192 CVector3 direction;
2193 CVector3 orthDirection;
2194 CVector3 point;
2195 double dist;
2196
2197 stopRequest = false;
2198
2199 // negative x limit
2200 cProgressText::ProgressStatusText(
2201 QObject::tr("bounding box as limit"), QObject::tr("Negative X Limit"), 0.0 / 6.0);
2202 direction = CVector3(1, 0, 0);
2203 orthDirection = CVector3(0, 1, 0);
2204 point = CVector3(outerBoundingMin.x, boundingCenter.y, boundingCenter.z);
2205 dist = CalculateDistanceMinPlane(params, fractals, point, direction, orthDirection, &stopRequest);
2206 double minX = point.x + dist;
2207
2208 // negative y limit
2209 cProgressText::ProgressStatusText(
2210 QObject::tr("bounding box as limit"), QObject::tr("Negative Y Limit"), 1.0 / 6.0);
2211 direction = CVector3(0, 1, 0);
2212 orthDirection = CVector3(0, 0, 1);
2213 point = CVector3(boundingCenter.x, outerBoundingMin.y, boundingCenter.z);
2214 dist = CalculateDistanceMinPlane(params, fractals, point, direction, orthDirection, &stopRequest);
2215 double minY = point.y + dist;
2216
2217 // negative z limit
2218 cProgressText::ProgressStatusText(
2219 QObject::tr("bounding box as limit"), QObject::tr("Negative Z Limit"), 2.0 / 6.0);
2220 direction = CVector3(0, 0, 1);
2221 orthDirection = CVector3(1, 0, 0);
2222 point = CVector3(boundingCenter.x, boundingCenter.y, outerBoundingMin.z);
2223 dist = CalculateDistanceMinPlane(params, fractals, point, direction, orthDirection, &stopRequest);
2224 double minZ = point.z + dist;
2225
2226 // positive x limit
2227 cProgressText::ProgressStatusText(
2228 QObject::tr("bounding box as limit"), QObject::tr("Positive X Limit"), 3.0 / 6.0);
2229 direction = CVector3(-1, 0, 0);
2230 orthDirection = CVector3(0, -1, 0);
2231 point = CVector3(outerBoundingMax.x, boundingCenter.y, boundingCenter.z);
2232 dist = CalculateDistanceMinPlane(params, fractals, point, direction, orthDirection, &stopRequest);
2233 double maxX = point.x - dist;
2234
2235 // positive y limit
2236 cProgressText::ProgressStatusText(
2237 QObject::tr("bounding box as limit"), QObject::tr("Positive Y Limit"), 4.0 / 6.0);
2238 direction = CVector3(0, -1, 0);
2239 orthDirection = CVector3(0, 0, -1);
2240 point = CVector3(boundingCenter.x, outerBoundingMax.y, boundingCenter.z);
2241 dist = CalculateDistanceMinPlane(params, fractals, point, direction, orthDirection, &stopRequest);
2242 double maxY = point.y - dist;
2243
2244 // positive z limit
2245 cProgressText::ProgressStatusText(
2246 QObject::tr("bounding box as limit"), QObject::tr("Positive Z Limit"), 5.0 / 6.0);
2247 direction = CVector3(0, 0, -1);
2248 orthDirection = CVector3(-1, 0, 0);
2249 point = CVector3(boundingCenter.x, boundingCenter.y, outerBoundingMax.z);
2250 dist = CalculateDistanceMinPlane(params, fractals, point, direction, orthDirection, &stopRequest);
2251 double maxZ = point.z - dist;
2252
2253 double medX = (maxX + minX) / 2.0;
2254 double medY = (maxY + minY) / 2.0;
2255 double medZ = (maxZ + minZ) / 2.0;
2256 double rangeX = maxX - minX;
2257 double rangeY = maxY - minY;
2258 double rangeZ = maxZ - minZ;
2259
2260 gPar->Set("limit_min", CVector3(medX - rangeX * 0.6, medY - rangeY * 0.6, medZ - rangeZ * 0.6));
2261 gPar->Set("limit_max", CVector3(medX + rangeX * 0.6, medY + rangeY * 0.6, medZ + rangeZ * 0.6));
2262
2263 cProgressText::ProgressStatusText(QObject::tr("bounding box as limit"), QObject::tr("Done"), 1.0);
2264 SynchronizeInterface(gPar, gParFractal, qInterface::write);
2265 }
2266
NewPrimitive(const QString & primitiveType,int index)2267 void cInterface::NewPrimitive(const QString &primitiveType, int index)
2268 {
2269 QString primitiveName = QString("primitive_") + primitiveType;
2270 QString uiFileName = systemDirectories.sharedDir + "formula" + QDir::separator() + "ui"
2271 + QDir::separator() + primitiveName + ".ui";
2272 fractal::enumObjectType objectType = PrimitiveNameToEnum(primitiveType);
2273
2274 int newId = 0;
2275 if (index == 0)
2276 {
2277 // look for the lowest free id
2278 bool occupied = true;
2279
2280 while (occupied)
2281 {
2282 newId++;
2283 occupied = false;
2284 for (const auto &primitiveItem : listOfPrimitives)
2285 {
2286 if (objectType == primitiveItem.type && newId == primitiveItem.id) occupied = true;
2287 }
2288 }
2289 }
2290 else
2291 {
2292 newId = index; // use given index
2293 }
2294
2295 // name for new primitive
2296 QString primitiveFullName = primitiveName + "_" + QString::number(newId);
2297
2298 sPrimitiveItem newItem(objectType, newId, primitiveFullName);
2299 listOfPrimitives.append(newItem);
2300
2301 // main widget for primitive
2302 QWidget *mainWidget =
2303 new QWidget(mainWindow->ui->widgetDockFractal->GetContainerWithPrimitives());
2304 mainWidget->setObjectName(QString("widgetmain_") + primitiveFullName);
2305 QVBoxLayout *layout = new QVBoxLayout();
2306 mainWidget->setLayout(layout);
2307
2308 QHBoxLayout *buttonsLayout = new QHBoxLayout();
2309 layout->addLayout(buttonsLayout);
2310
2311 QPushButton *setPositionButton = new QPushButton(
2312 QObject::tr("Set position of\n%1 # %2\nby mouse pointer").arg(primitiveType).arg(newId),
2313 mainWidget);
2314 setPositionButton->setObjectName(QString("setPositionButton_") + primitiveFullName);
2315 buttonsLayout->addWidget(setPositionButton);
2316
2317 QPushButton *deleteButton = new QPushButton(
2318 QObject::tr("Delete\n") + primitiveType + " # " + QString::number(newId), mainWidget);
2319 deleteButton->setObjectName(QString("deleteButton_") + primitiveFullName);
2320 buttonsLayout->addWidget(deleteButton);
2321
2322 QHBoxLayout *buttonsLayout2 = new QHBoxLayout();
2323 layout->addLayout(buttonsLayout2);
2324
2325 QPushButton *alignButton = new QPushButton(QObject::tr("Align rotation to camera"), mainWidget);
2326 alignButton->setObjectName(QString("alignButton_") + primitiveFullName);
2327 buttonsLayout2->addWidget(alignButton);
2328
2329 MyGroupBox *groupBox = new MyGroupBox(mainWidget);
2330 groupBox->setObjectName(QString("groupCheck_") + primitiveFullName + "_enabled");
2331 groupBox->setCheckable(true);
2332 groupBox->setTitle(primitiveType + " # " + QString::number(newId));
2333 layout->addWidget(groupBox);
2334
2335 QVBoxLayout *layoutGroupBox = new QVBoxLayout();
2336 groupBox->setLayout(layoutGroupBox);
2337
2338 // load ui
2339 MyUiLoader loader;
2340 QFile uiFile(uiFileName);
2341 if (uiFile.exists())
2342 {
2343 uiFile.open(QFile::ReadOnly);
2344 QWidget *primitiveWidget = loader.load(&uiFile);
2345 uiFile.close();
2346 primitiveWidget->setObjectName(QString("widgetui_") + primitiveFullName);
2347 layoutGroupBox->addWidget(primitiveWidget);
2348
2349 // put widget into layout
2350 QVBoxLayout *primitivesLayout = mainWindow->ui->widgetDockFractal->GetLayoutWithPrimitives();
2351 primitivesLayout->addWidget(mainWidget);
2352
2353 // rename widgets
2354 QList<QWidget *> listOfWidgets = primitiveWidget->findChildren<QWidget *>();
2355 for (auto &widget : listOfWidgets)
2356 {
2357 QString name = widget->objectName();
2358 int firstDash = name.indexOf('_');
2359 QString newName = name.insert(firstDash + 1, primitiveFullName + "_");
2360 widget->setObjectName(newName);
2361 }
2362
2363 connect(deleteButton, SIGNAL(clicked()), mainWindow, SLOT(slotPressedButtonDeletePrimitive()));
2364 connect(setPositionButton, SIGNAL(clicked()), mainWindow,
2365 SLOT(slotPressedButtonSetPositionPrimitive()));
2366 connect(
2367 alignButton, SIGNAL(clicked()), mainWindow, SLOT(slotPressedButtonAlignPrimitiveAngle()));
2368
2369 // adding parameters
2370 if (index == 0) // for only new primitive
2371 {
2372 InitPrimitiveParams(objectType, primitiveFullName, gPar);
2373 gPar->Set(primitiveFullName + "_enabled", true);
2374 }
2375
2376 mainWindow->automatedWidgets->ConnectSignalsForSlidersInWindow(mainWidget);
2377 SynchronizeInterfaceWindow(mainWidget, gPar, qInterface::write);
2378
2379 if (gPar->Get<bool>("ui_colorize"))
2380 {
2381 cInterface::ColorizeGroupBoxes(
2382 groupBox, gPar->Get<int>("ui_colorize_random_seed") + Random(65535));
2383 }
2384
2385 ComboMouseClickUpdate();
2386 }
2387 else
2388 {
2389 cErrorMessage::showMessage(QObject::tr("Can't open file ") + uiFileName
2390 + QObject::tr(" Primitive object ui file can't be loaded"),
2391 cErrorMessage::errorMessage, mainWindow);
2392 }
2393 }
2394
DeletePrimitive(const QString & primitiveName)2395 void cInterface::DeletePrimitive(const QString &primitiveName)
2396 {
2397 QString primitiveWidgetName = QString("widgetmain_") + primitiveName;
2398 fractal::enumObjectType objectType = fractal::objNone;
2399
2400 // delete widget
2401 QWidget *primitiveWidget =
2402 mainWindow->ui->widgetDockFractal->GetContainerWithPrimitives()->findChild<QWidget *>(
2403 primitiveWidgetName);
2404 delete primitiveWidget;
2405
2406 // remove item from list
2407 for (int i = 0; i < listOfPrimitives.size(); i++)
2408 {
2409 if (primitiveName == listOfPrimitives.at(i).name)
2410 {
2411 objectType = listOfPrimitives.at(i).type;
2412 listOfPrimitives.removeAt(i);
2413 }
2414 }
2415
2416 DeletePrimitiveParams(objectType, primitiveName, gPar);
2417 ComboMouseClickUpdate();
2418 }
2419
RebuildPrimitives(std::shared_ptr<cParameterContainer> par)2420 void cInterface::RebuildPrimitives(std::shared_ptr<cParameterContainer> par)
2421 {
2422 // clear all widgets
2423 for (const auto &primitiveItem : listOfPrimitives)
2424 {
2425 QString widgetName = QString("widgetmain_") + primitiveItem.name;
2426 QWidget *widget =
2427 mainWindow->ui->widgetDockFractal->GetContainerWithPrimitives()->findChild<QWidget *>(
2428 widgetName);
2429 delete widget;
2430 }
2431 listOfPrimitives.clear();
2432
2433 QList<QString> listOfParameters = par->GetListOfParameters();
2434 for (auto ¶meterName : listOfParameters)
2435 {
2436 if (parameterName.left(parameterName.indexOf('_')) == "primitive")
2437 {
2438 QStringList split = parameterName.split('_');
2439 QString primitiveName = split.at(0) + "_" + split.at(1) + "_" + split.at(2);
2440 QString objectTypeString = split.at(1);
2441 int index = split.at(2).toInt();
2442
2443 bool found = false;
2444 for (const auto &listOfPrimitive : listOfPrimitives)
2445 {
2446 if (listOfPrimitive.name == primitiveName)
2447 {
2448 found = true;
2449 break;
2450 }
2451 }
2452
2453 if (!found)
2454 {
2455 NewPrimitive(objectTypeString, index);
2456 }
2457 }
2458 }
2459 }
2460
ComboMouseClickUpdate() const2461 void cInterface::ComboMouseClickUpdate() const
2462 {
2463 QComboBox *combo = mainWindow->ui->comboBox_mouse_click_function;
2464 int lastIndex = combo->currentIndex();
2465
2466 combo->clear();
2467 QList<QVariant> item;
2468
2469 item.clear();
2470 item.append(int(RenderedImage::clickDoNothing));
2471 combo->addItem(QObject::tr("No action"), item);
2472
2473 item.clear();
2474 item.append(int(RenderedImage::clickMoveCamera));
2475 combo->addItem(QObject::tr("Move the camera"), item);
2476
2477 item.clear();
2478 item.append(int(RenderedImage::clickFogVisibility));
2479 combo->addItem(QObject::tr("Set fog visibility"), item);
2480
2481 item.clear();
2482 item.append(int(RenderedImage::clickDOFFocus));
2483 combo->addItem(QObject::tr("Set DOF focus"), item);
2484
2485 item.clear();
2486 item.append(int(RenderedImage::clickGetJuliaConstant));
2487 combo->addItem(QObject::tr("Get Julia constant"), item);
2488
2489 QList<int> listOfLights = cLights::GetListOfLights(gPar);
2490
2491 for (int lightIndex : listOfLights)
2492 {
2493 item.clear();
2494 item.append(int(RenderedImage::clickPlaceLight));
2495 item.append(lightIndex);
2496 combo->addItem(QObject::tr("Place light #%1").arg(lightIndex), item);
2497 }
2498
2499 item.clear();
2500 item.append(int(RenderedImage::clickPlaceRandomLightCenter));
2501 combo->addItem(QObject::tr("Place random light center"), item);
2502
2503 item.clear();
2504 item.append(int(RenderedImage::clickGetPoint));
2505 combo->addItem(QObject::tr("Get point coordinates"), item);
2506
2507 item.clear();
2508 item.append(int(RenderedImage::clickWrapLimitsAroundObject));
2509 combo->addItem(QObject::tr("Wrap Limits around object"), item);
2510
2511 if (listOfPrimitives.size() > 0)
2512 {
2513 for (const auto &primitiveItem : listOfPrimitives)
2514 {
2515 QString primitiveName = PrimitiveNames(primitiveItem.type);
2516 int index = primitiveItem.id;
2517 QString comboItemString =
2518 QString(QObject::tr("Place ")) + primitiveName + QString(" #") + QString::number(index);
2519 item.clear();
2520 item.append(int(RenderedImage::clickPlacePrimitive));
2521 item.append(int(primitiveItem.type));
2522 item.append(primitiveItem.id);
2523 item.append(primitiveItem.name);
2524 combo->addItem(comboItemString, item);
2525 }
2526 }
2527
2528 if (lastIndex < combo->count())
2529 {
2530 combo->setCurrentIndex(lastIndex);
2531 }
2532 }
2533
QuitApplicationDialog()2534 bool cInterface::QuitApplicationDialog()
2535 {
2536 bool quit = false;
2537 int closeResult;
2538 bool quitDoNotAskAgain = gPar->Get<bool>("quit_do_not_ask_again");
2539 QMessageBox *messageBox = nullptr;
2540 QAbstractButton *btnYesAndDoNotAskAgain = nullptr;
2541 if (quitDoNotAskAgain)
2542 {
2543 closeResult = QMessageBox::Ok;
2544 }
2545 else
2546 {
2547 messageBox = new QMessageBox(mainWindow);
2548 QString messageText = QObject::tr("Are you sure to close the application?");
2549 messageBox->setText(messageText);
2550 messageBox->setWindowTitle(QObject::tr("Quit?"));
2551 messageBox->setIcon(QMessageBox::Question);
2552 messageBox->addButton(QMessageBox::Ok);
2553 messageBox->addButton(QMessageBox::Cancel);
2554 btnYesAndDoNotAskAgain =
2555 messageBox->addButton(QObject::tr("Yes, don't ask again"), QMessageBox::YesRole);
2556 messageBox->setDefaultButton(QMessageBox::Ok);
2557 closeResult = messageBox->exec();
2558 }
2559
2560 switch (closeResult)
2561 {
2562 case QMessageBox::Cancel:
2563 {
2564 // nothing
2565 break;
2566 }
2567 case QMessageBox::Yes:
2568 default:
2569 {
2570 if (messageBox && messageBox->clickedButton() == btnYesAndDoNotAskAgain)
2571 gPar->Set("quit_do_not_ask_again", true);
2572 DisablePeriodicRefresh();
2573 stopRequest = true;
2574 systemData.globalStopRequest = true;
2575 gQueue->stopRequest = true;
2576 WriteLog("Quit application", 2);
2577 // save applications settings
2578 cSettings parSettings(cSettings::formatAppSettings);
2579 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2580 parSettings.CreateText(gPar, gParFractal, gAnimFrames, gKeyframes);
2581 parSettings.SaveToFile(systemData.GetIniFile());
2582
2583 while (cRenderJob::GetRunningJobCount() > 0)
2584 {
2585 gApplication->processEvents();
2586 }
2587
2588 QFile::remove(systemDirectories.GetAutosaveFile());
2589
2590 if (detachedWindow)
2591 {
2592 settings.setValue("detachedWindowGeometry", detachedWindow->saveGeometry());
2593 }
2594
2595 ClearNetRenderCache();
2596
2597 gApplication->quit();
2598 quit = true;
2599 break;
2600 }
2601 }
2602 if (messageBox) delete messageBox;
2603 return quit;
2604 }
2605
AutoRecovery() const2606 void cInterface::AutoRecovery() const
2607 {
2608 if (QFile::exists(systemDirectories.GetAutosaveFile()))
2609 {
2610 // auto recovery dialog
2611 QMessageBox::StandardButton reply;
2612 reply = QMessageBox::question(mainWindow->ui->centralwidget, QObject::tr("Auto recovery"),
2613 QObject::tr(
2614 "Application has not been closed properly\nDo you want to recover your latest work?"),
2615 QMessageBox::Yes | QMessageBox::No);
2616
2617 if (reply == QMessageBox::Yes)
2618 {
2619 cSettings parSettings(cSettings::formatFullText);
2620 gInterfaceReadyForSynchronization = false;
2621 parSettings.LoadFromFile(systemDirectories.GetAutosaveFile());
2622 parSettings.Decode(gPar, gParFractal, gAnimFrames, gKeyframes);
2623 gMainInterface->RebuildPrimitives(gPar);
2624 materialListModel->Regenerate();
2625 mainWindow->ui->widgetEffects->RegenerateLights();
2626 SynchronizeInterface(gPar, gParFractal, qInterface::write);
2627 gInterfaceReadyForSynchronization = true;
2628 gFlightAnimation->RefreshTable();
2629 gKeyframeAnimation->RefreshTable();
2630 }
2631 else
2632 {
2633 return;
2634 }
2635 }
2636 }
2637
2638 // ReSharper disable once CppMemberFunctionMayBeStatic
DataFolderUpgrade() const2639 bool cInterface::DataFolderUpgrade() const
2640 {
2641 #ifndef _WIN32
2642 if (systemData.IsUpgraded()) return false; // already upgraded, nothing to do
2643 bool upgradeDoNotAskAgain = gPar->Get<bool>("upgrade_do_not_ask_again");
2644 if (upgradeDoNotAskAgain) return false; // user does not want to upgrade ever
2645
2646 QAbstractButton *btnNoAndDoNotAskAgain = nullptr;
2647 QMessageBox *messageBox = new QMessageBox(mainWindow);
2648 QString messageText = QObject::tr(
2649 "In Mandelbulber 2.10 the default data structure changed for linux and MacOS:\n"
2650 "Instead of keeping all working folders/files in ~/.mandelbulber these are now split into"
2651 "<ul><li><b>.mandelbulber</b> for program internal folders/files:<br>"
2652 "undo, toolbar, queue, thumbnails, mandelbulber.ini, miscellaneous meta files</li>"
2653 "<li><b>mandelbulber</b> for user defined folders/files:<br>"
2654 "settings, images, materials, slices, animation, textures</li></ul>\n"
2655 "Do you want to upgrade now to this new structure? Program will restart after upgrade.");
2656 messageBox->setText(messageText);
2657 messageBox->setTextFormat(Qt::RichText);
2658 messageBox->setWindowTitle(QObject::tr("Data folder upgrade"));
2659 messageBox->setIcon(QMessageBox::Question);
2660 messageBox->addButton(QMessageBox::Ok);
2661 messageBox->addButton(QMessageBox::Cancel);
2662 btnNoAndDoNotAskAgain =
2663 messageBox->addButton(QObject::tr("No, don't ask again"), QMessageBox::YesRole);
2664 messageBox->setDefaultButton(QMessageBox::Ok);
2665 int dialogResult = messageBox->exec();
2666
2667 switch (dialogResult)
2668 {
2669 case QMessageBox::Cancel:
2670 default:
2671 {
2672 if (messageBox->clickedButton() == btnNoAndDoNotAskAgain)
2673 gPar->Set("upgrade_do_not_ask_again", true);
2674 break;
2675 }
2676 case QMessageBox::Ok:
2677 {
2678 systemData.Upgrade();
2679 // Needs restart
2680 QProcess::startDetached(qApp->arguments()[0], QStringList());
2681 delete messageBox;
2682 return true;
2683 break;
2684 }
2685 }
2686 delete messageBox;
2687 #endif
2688 return false;
2689 }
2690
OptimizeStepFactor(double qualityTarget)2691 void cInterface::OptimizeStepFactor(double qualityTarget)
2692 {
2693 DisablePeriodicRefresh();
2694
2695 // check if main image is not used by other rendering process
2696 if (mainImage->IsUsed())
2697 {
2698 cErrorMessage::showMessage(
2699 QObject::tr("Rendering engine is busy. Stop unfinished rendering before starting new one"),
2700 cErrorMessage::errorMessage);
2701 return;
2702 }
2703
2704 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2705 gUndo->Store(gPar, gParFractal);
2706
2707 auto tempParam = std::make_shared<cParameterContainer>();
2708 *tempParam = *gPar;
2709 auto tempFractal = std::make_shared<cFractalContainer>();
2710 *tempFractal = *gParFractal;
2711
2712 // disabling all slow effects
2713 tempParam->Set("light1_cast_shadows", false);
2714 tempParam->Set("ambient_occlusion", false);
2715 tempParam->Set("DOF_enabled", false);
2716 tempParam->Set("iteration_threshold_mode", false);
2717 tempParam->Set("raytraced_reflections", false);
2718 tempParam->Set("textured_background", false);
2719 tempParam->Set("iteration_fog_enable", false);
2720 tempParam->Set("fake_lights_enabled", false);
2721 tempParam->Set("main_light_volumetric_enabled", false);
2722 tempParam->Set("opencl_mode", 0); // disable OpenCL
2723 for (int i = 1; i <= 4; i++)
2724 {
2725 tempParam->Set("aux_light_enabled", i, false);
2726 tempParam->Set("aux_light_volumetric_enabled", i, false);
2727 }
2728
2729 int maxDimension = max(gPar->Get<int>("image_width"), gPar->Get<int>("image_height"));
2730 if (maxDimension == 0) maxDimension = 1;
2731 int newWidth = double(gPar->Get<int>("image_width")) / maxDimension * 256.0;
2732 int newHeight = double(gPar->Get<int>("image_height")) / maxDimension * 256.0;
2733
2734 tempParam->Set("image_width", newWidth);
2735 tempParam->Set("image_height", newHeight);
2736 tempParam->Set("detail_level", 4.0);
2737
2738 int scanCount = 0;
2739 double DEFactor = 1.0;
2740 double step = 1.0;
2741
2742 std::unique_ptr<cRenderJob> renderJob(
2743 new cRenderJob(tempParam, tempFractal, mainImage, &stopRequest, renderedImage));
2744 QObject::connect(renderJob.get(), SIGNAL(updateStatistics(cStatistics)),
2745 mainWindow->ui->widgetDockStatistics, SLOT(slotUpdateStatistics(cStatistics)));
2746 connect(renderJob.get(), SIGNAL(updateImage()), renderedImage, SLOT(update()));
2747
2748 cRenderingConfiguration config;
2749 config.DisableRefresh();
2750 config.DisableProgressiveRender();
2751 config.DisableNetRender();
2752 config.SetMaxRenderTime(5.0);
2753
2754 renderJob->Init(cRenderJob::still, config);
2755
2756 cProgressText::ProgressStatusText(QObject::tr("Looking for optimal DE factor"),
2757 QString("Percentage of wrong distance estimations: ") + QString::number(0.0), 0.0,
2758 cProgressText::progress_IMAGE);
2759
2760 stopRequest = false;
2761
2762 double missedDE = 0.0;
2763
2764 for (int i = 0; i < 100; i++)
2765 {
2766 if (stopRequest || systemData.globalStopRequest) return;
2767 scanCount++;
2768 tempParam->Set("DE_factor", DEFactor);
2769
2770 gPar->Set("DE_factor", DEFactor);
2771 SynchronizeInterface(gPar, gParFractal, qInterface::write);
2772
2773 renderJob->UpdateParameters(tempParam, tempFractal);
2774 renderJob->Execute();
2775 missedDE = renderJob->GetStatistics().GetMissedDEPercentage();
2776
2777 if (missedDE < qualityTarget)
2778 {
2779 if (scanCount == 1)
2780 {
2781 if (step < 10000)
2782 {
2783 DEFactor = DEFactor * 2.0;
2784 step = step * 2.0;
2785 scanCount = 0;
2786 continue;
2787 }
2788 else
2789 {
2790 return;
2791 }
2792 }
2793 else
2794 {
2795 if (step < 0.05 * DEFactor) break;
2796 DEFactor += step;
2797 }
2798 }
2799
2800 double progress = 1.0 - 1.0 / (1.0 + pow(qualityTarget / (missedDE - qualityTarget), 2.0));
2801 cProgressText::ProgressStatusText(QObject::tr("Looking for optimal DE factor"),
2802 QObject::tr("Percentage of wrong distance estimations: %1").arg(missedDE), progress,
2803 cProgressText::progress_IMAGE);
2804
2805 step /= 2.0;
2806 DEFactor -= step;
2807 }
2808
2809 gPar->Set("DE_factor", DEFactor);
2810 SynchronizeInterface(gPar, gParFractal, qInterface::write);
2811 cProgressText::ProgressStatusText(QObject::tr("Idle"),
2812 QObject::tr("Optimal DE factor is: %1 which gives %2% of bad distance estimations")
2813 .arg(DEFactor)
2814 .arg(missedDE),
2815 1.0, cProgressText::progress_IMAGE);
2816
2817 ReEnablePeriodicRefresh();
2818 }
2819
ResetFormula(int fractalNumber) const2820 void cInterface::ResetFormula(int fractalNumber) const
2821 {
2822 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2823 gUndo->Store(gPar, gParFractal, gAnimFrames, gKeyframes);
2824 std::shared_ptr<cParameterContainer> fractal = gParFractal->at(fractalNumber);
2825
2826 QStringList exclude = {"formula_code"};
2827 fractal->ResetAllToDefault(exclude);
2828
2829 QStringList listToReset = {"formula_iterations", "formula_weight", "formula_start_iteration",
2830 "formula_stop_iteration", "julia_mode", "julia_c", "fractal_constant_factor", "initial_waxis",
2831 "formula_position", "formula_rotation", "formula_repeat", "formula_scale",
2832 "dont_add_c_constant", "check_for_bailout"};
2833
2834 for (int i = 0; i < listToReset.size(); i++)
2835 {
2836 cOneParameter oneParameter =
2837 gPar->GetAsOneParameter(listToReset[i] + QString("_%1").arg(fractalNumber + 1));
2838 oneParameter.SetMultiVal(oneParameter.GetMultiVal(valueDefault), valueActual);
2839 gPar->SetFromOneParameter(listToReset[i] + QString("_%1").arg(fractalNumber + 1), oneParameter);
2840 }
2841
2842 gUndo->Store(gPar, gParFractal, gAnimFrames, gKeyframes);
2843 SynchronizeInterface(gPar, gParFractal, qInterface::write);
2844 }
2845
PeriodicRefresh()2846 void cInterface::PeriodicRefresh()
2847 {
2848 if (!mouseDragData.draggingStarted)
2849 {
2850 if (mainWindow->ui->widgetDockNavigation->AutoRefreshIsChecked())
2851 {
2852 // check if something was changed in settings
2853 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2854 cSettings tempSettings(cSettings::formatCondensedText);
2855 tempSettings.CreateText(gPar, gParFractal);
2856 QString newHash = tempSettings.GetHashCode();
2857
2858 if (newHash != autoRefreshLastHash)
2859 {
2860 autoRefreshLastHash = newHash;
2861 StartRender();
2862 }
2863 }
2864 }
2865
2866 autoRefreshTimer->start(int(gPar->Get<double>("auto_refresh_period") * 1000.0));
2867 }
2868
DisablePeriodicRefresh()2869 void cInterface::DisablePeriodicRefresh()
2870 {
2871 if (mainWindow)
2872 {
2873 autoRefreshLastState = mainWindow->ui->widgetDockNavigation->AutoRefreshIsChecked();
2874 mainWindow->ui->widgetDockNavigation->AutoRefreshSetChecked(false);
2875 gPar->Set("auto_refresh", false);
2876 }
2877 }
2878
ReEnablePeriodicRefresh()2879 void cInterface::ReEnablePeriodicRefresh()
2880 {
2881 SynchronizeInterface(gPar, gParFractal, qInterface::read);
2882 cSettings tempSettings(cSettings::formatCondensedText);
2883 tempSettings.CreateText(gPar, gParFractal);
2884 autoRefreshLastHash = tempSettings.GetHashCode();
2885 if (autoRefreshLastState)
2886 {
2887 mainWindow->ui->widgetDockNavigation->AutoRefreshSetChecked(true);
2888 gPar->Set("auto_refresh", true);
2889 }
2890 }
2891
InitPeriodicRefresh()2892 void cInterface::InitPeriodicRefresh()
2893 {
2894 autoRefreshTimer = new QTimer(mainWindow);
2895 autoRefreshTimer->setSingleShot(true);
2896 connect(autoRefreshTimer, SIGNAL(timeout()), mainWindow, SLOT(slotAutoRefresh()));
2897 autoRefreshTimer->start(int(gPar->Get<double>("auto_refresh_period") * 1000.0));
2898 }
2899
InitMaterialsUi()2900 void cInterface::InitMaterialsUi()
2901 {
2902 materialEditor = new cMaterialEditor(mainWindow->ui->scrollArea_material);
2903
2904 if (gPar->Get<bool>("ui_colorize"))
2905 materialEditor->Colorize(gPar->Get<int>("ui_colorize_random_seed"));
2906
2907 mainWindow->ui->verticalLayout_materials->addWidget(materialEditor);
2908
2909 materialListModel = new cMaterialItemModel(mainWindow->ui->scrollArea_material);
2910 materialListModel->AssignContainer(gPar);
2911 mainWindow->ui->widget_material_list_view->SetModel(materialListModel);
2912
2913 if (systemData.settingsLoadedFromCLI)
2914 {
2915 materialListModel->Regenerate();
2916 }
2917 else
2918 {
2919 materialListModel->insertRows(0, 1, QModelIndex());
2920 }
2921
2922 materialEditor->AssignMaterial(gPar, 1);
2923 connect(materialEditor, SIGNAL(materialChanged(int)), materialListModel,
2924 SLOT(slotMaterialChanged(int)));
2925
2926 connect(mainWindow->ui->widget_material_list_view, SIGNAL(materialSelected(int)), mainWindow,
2927 SLOT(slotMaterialSelected(int)));
2928
2929 connect(mainWindow->ui->widget_material_list_view, SIGNAL(materialEdited()), mainWindow,
2930 SLOT(slotMaterialEdited()));
2931 }
2932
MaterialSelected(int matIndex)2933 void cInterface::MaterialSelected(int matIndex)
2934 {
2935 if (materialEditor)
2936 {
2937 delete materialEditor;
2938 materialEditor = new cMaterialEditor(mainWindow->ui->scrollArea_material);
2939
2940 if (gPar->Get<bool>("ui_colorize"))
2941 materialEditor->Colorize(gPar->Get<int>("ui_colorize_random_seed"));
2942
2943 mainWindow->ui->verticalLayout_materials->addWidget(materialEditor);
2944 materialEditor->AssignMaterial(gPar, matIndex);
2945 connect(materialEditor, SIGNAL(materialChanged(int)), materialListModel,
2946 SLOT(slotMaterialChanged(int)));
2947
2948 if (matIndex != lastSelectedMaterial)
2949 {
2950 mainWindow->ui->dockWidget_materialEditor->raise();
2951 lastSelectedMaterial = matIndex;
2952 }
2953 }
2954 }
2955
StartupDefaultSettings()2956 void cInterface::StartupDefaultSettings()
2957 {
2958 gPar->Set("DE_factor", 1.0);
2959 gPar->Set("ambient_occlusion_enabled", true);
2960 gPar->Set("ambient_occlusion_mode", int(params::AOModeScreenSpace));
2961 gPar->Set("ambient_occlusion_quality", 4);
2962 gPar->Set("raytraced_reflections", true);
2963 gPar->Set("detail_level", 2.0);
2964 }
2965
DisableJuliaPointMode() const2966 void cInterface::DisableJuliaPointMode() const
2967 {
2968 QList<QVariant> itemMouseMove;
2969 itemMouseMove.append(int(RenderedImage::clickMoveCamera));
2970
2971 QList<QVariant> itemJuliaMode;
2972 itemJuliaMode.append(int(RenderedImage::clickGetJuliaConstant));
2973
2974 if (mainWindow->ui->comboBox_mouse_click_function->currentData() == itemJuliaMode)
2975 {
2976 int index = mainWindow->ui->comboBox_mouse_click_function->findData(itemMouseMove);
2977 mainWindow->ui->comboBox_mouse_click_function->setCurrentIndex(index);
2978 renderedImage->setClickMode(itemMouseMove);
2979 }
2980 }
2981 // function to create icons with actual color in ColorButtons
2982
ConnectProgressAndStatisticsSignals() const2983 void cInterface::ConnectProgressAndStatisticsSignals() const
2984 {
2985 QObject::connect(gFlightAnimation,
2986 SIGNAL(updateProgressAndStatus(
2987 const QString &, const QString &, double, cProgressText::enumProgressType)),
2988 mainWindow,
2989 SLOT(slotUpdateProgressAndStatus(
2990 const QString &, const QString &, double, cProgressText::enumProgressType)));
2991 QObject::connect(gFlightAnimation, SIGNAL(updateProgressHide(cProgressText::enumProgressType)),
2992 mainWindow, SLOT(slotUpdateProgressHide(cProgressText::enumProgressType)));
2993 QObject::connect(gFlightAnimation, SIGNAL(updateStatistics(cStatistics)),
2994 mainWindow->ui->widgetDockStatistics, SLOT(slotUpdateStatistics(cStatistics)));
2995 QObject::connect(gKeyframeAnimation,
2996 SIGNAL(updateProgressAndStatus(
2997 const QString &, const QString &, double, cProgressText::enumProgressType)),
2998 mainWindow,
2999 SLOT(slotUpdateProgressAndStatus(
3000 const QString &, const QString &, double, cProgressText::enumProgressType)));
3001 QObject::connect(gKeyframeAnimation, SIGNAL(updateProgressHide(cProgressText::enumProgressType)),
3002 mainWindow, SLOT(slotUpdateProgressHide(cProgressText::enumProgressType)));
3003 QObject::connect(gKeyframeAnimation, SIGNAL(updateStatistics(cStatistics)),
3004 mainWindow->ui->widgetDockStatistics, SLOT(slotUpdateStatistics(cStatistics)));
3005 }
3006
MakeIconForButton(QColor & color,QPushButton * pushbutton)3007 void MakeIconForButton(QColor &color, QPushButton *pushbutton)
3008 {
3009 const int w = 40;
3010 const int h = 15;
3011 QPixmap pix(w, h);
3012 QPainter painter(&pix);
3013 painter.fillRect(QRect(0, 0, w, h), color);
3014 painter.drawRect(0, 0, w - 1, h - 1);
3015 QIcon icon(pix);
3016 pushbutton->setIcon(icon);
3017 pushbutton->setIconSize(QSize(w, h));
3018 }
3019
DetachMainImageWidget()3020 void cInterface::DetachMainImageWidget()
3021 {
3022 if (!detachedWindow)
3023 {
3024 detachedWindow = new cDetachedWindow;
3025 connect(detachedWindow, SIGNAL(ReturnToOrigin()),
3026 mainWindow->ui->actionDetach_image_from_main_window, SLOT(toggle()));
3027 connect(detachedWindow, SIGNAL(ReturnToOrigin()), mainWindow, SLOT(slotDetachMainImage()));
3028 }
3029 mainWindow->ui->verticalLayout->removeWidget(mainWindow->ui->widgetWithImage);
3030 detachedWindow->InstallImageWidget(mainWindow->ui->widgetWithImage);
3031 detachedWindow->restoreGeometry(settings.value("detachedWindowGeometry").toByteArray());
3032 detachedWindow->show();
3033 // mainWindow->centralWidget()->hide();
3034 gPar->Set("image_detached", true);
3035 }
3036
AttachMainImageWidget()3037 void cInterface::AttachMainImageWidget()
3038 {
3039 if (detachedWindow)
3040 {
3041 detachedWindow->RemoveImageWidget(mainWindow->ui->widgetWithImage);
3042 mainWindow->ui->verticalLayout->addWidget(mainWindow->ui->widgetWithImage);
3043 settings.setValue("detachedWindowGeometry", detachedWindow->saveGeometry());
3044 // mainWindow->centralWidget()->show();
3045 gPar->Set("image_detached", false);
3046 }
3047 }
3048
CameraMovementModeChanged(int index)3049 void cInterface::CameraMovementModeChanged(int index)
3050 {
3051 renderedImage->SetCameraMovementMode(index);
3052 }
3053
ColorizeGroupBoxes(QWidget * window,int randomSeed)3054 void cInterface::ColorizeGroupBoxes(QWidget *window, int randomSeed)
3055 {
3056 QList<QGroupBox *> widgets;
3057 widgets = window->findChildren<QGroupBox *>();
3058 if (qobject_cast<QGroupBox *>(window)) // check if QGroupBox
3059 {
3060 widgets.append(static_cast<QGroupBox *>(window));
3061 }
3062 QPalette palette = window->palette();
3063 QColor globalColor = palette.window().color();
3064 int brightness = globalColor.value();
3065
3066 int rBase = globalColor.red();
3067 int gBase = globalColor.green();
3068 int bBase = globalColor.blue();
3069
3070 cRandom random;
3071 random.Initialize(randomSeed);
3072
3073 foreach (QGroupBox *groupbox, widgets)
3074 {
3075 QColor buttonColor;
3076 if (brightness > 20)
3077 {
3078 int r = random.Random(40) + rBase - 20;
3079 r = clamp(r, 0, 255);
3080 int g = random.Random(40) + gBase - 20;
3081 g = clamp(g, 0, 255);
3082 int b = random.Random(40) + bBase - 20;
3083 b = clamp(b, 0, 255);
3084 buttonColor = QColor(r, g, b);
3085 }
3086 else
3087 {
3088 int r = random.Random(40) + rBase;
3089 r = clamp(r, 0, 255);
3090 int g = random.Random(40) + gBase;
3091 g = clamp(g, 0, 255);
3092 int b = random.Random(40) + bBase;
3093 b = clamp(b, 0, 255);
3094 buttonColor = QColor(r, g, b);
3095 }
3096
3097 QPalette newPalette(buttonColor);
3098 groupbox->setPalette(newPalette);
3099 groupbox->setAutoFillBackground(true);
3100 }
3101 }
3102
3103 // selective saving of settings (from selected widget)
SaveLocalSettings(const QWidget * widget)3104 void cInterface::SaveLocalSettings(const QWidget *widget)
3105 {
3106 QStringList listOfParameters = CreateListOfParametersInWidget(widget);
3107
3108 cSettings parSettings(cSettings::formatCondensedText);
3109 parSettings.SetListOfParametersToProcess(listOfParameters);
3110
3111 SynchronizeInterface(gPar, gParFractal, qInterface::read);
3112 parSettings.CreateText(gPar, gParFractal, gAnimFrames, gKeyframes);
3113
3114 QString proposedFilename = widget->objectName();
3115
3116 QFileDialog dialog(mainWindow);
3117 dialog.setOption(QFileDialog::DontUseNativeDialog);
3118 dialog.setFileMode(QFileDialog::AnyFile);
3119 dialog.setNameFilter(tr("Fractals (*.txt *.fract)"));
3120 dialog.setDirectory(
3121 QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).absolutePath()));
3122 dialog.selectFile(QDir::toNativeSeparators(proposedFilename));
3123 dialog.setAcceptMode(QFileDialog::AcceptSave);
3124 dialog.setWindowTitle(tr("Save settings from %1").arg(widget->objectName()));
3125 dialog.setDefaultSuffix("fract");
3126 QStringList filenames;
3127 if (dialog.exec())
3128 {
3129 filenames = dialog.selectedFiles();
3130 QString filename = QDir::toNativeSeparators(filenames.first());
3131 parSettings.SaveToFile(filename);
3132 }
3133 }
3134
LoadLocalSettings(const QWidget * widget)3135 void cInterface::LoadLocalSettings(const QWidget *widget)
3136 {
3137 QString proposedFilename = widget->objectName();
3138
3139 PreviewFileDialog dialog(mainWindow);
3140 dialog.setOption(QFileDialog::DontUseNativeDialog);
3141 dialog.setFileMode(QFileDialog::ExistingFile);
3142 dialog.setNameFilter(tr("Fractals (*.txt *.fract)"));
3143 dialog.setDirectory(
3144 QDir::toNativeSeparators(QFileInfo(systemData.lastSettingsFile).absolutePath()));
3145 dialog.selectFile(QDir::toNativeSeparators(proposedFilename));
3146 dialog.setAcceptMode(QFileDialog::AcceptOpen);
3147 dialog.setWindowTitle(tr("Load settings to %1").arg(widget->objectName()));
3148 QStringList filenames;
3149
3150 if (dialog.exec())
3151 {
3152 filenames = dialog.selectedFiles();
3153 QString filename = QDir::toNativeSeparators(filenames.first());
3154
3155 for (int i = 0; i < 2; i++) // repeat twice to refresh comboboxes and get new list of widgets
3156 {
3157 QStringList listOfParameters = CreateListOfParametersInWidget(widget);
3158
3159 SynchronizeInterface(
3160 gPar, gParFractal, qInterface::read); // update appParam before loading new settings
3161
3162 cSettings parSettings(cSettings::formatFullText);
3163 parSettings.SetListOfParametersToProcess(listOfParameters);
3164
3165 if (widget->objectName().contains("widgetTabFractal"))
3166 {
3167 int fractalIndex = widget->objectName().right(1).toInt();
3168 parSettings.SetFractalFormulaIndex(fractalIndex);
3169 }
3170
3171 DisablePeriodicRefresh();
3172 gInterfaceReadyForSynchronization = false;
3173 parSettings.LoadFromFile(filename);
3174 parSettings.Decode(gPar, gParFractal, gAnimFrames, gKeyframes);
3175
3176 SynchronizeInterface(gPar, gParFractal, qInterface::write);
3177 gInterfaceReadyForSynchronization = true;
3178
3179 ComboMouseClickUpdate();
3180 ReEnablePeriodicRefresh();
3181 }
3182 }
3183 }
3184
ResetLocalSettings(const QWidget * widget)3185 void cInterface::ResetLocalSettings(const QWidget *widget)
3186 {
3187 QStringList listOfParameters = CreateListOfParametersInWidget(widget);
3188
3189 for (QString fullParameterName : listOfParameters)
3190 {
3191 const int firstUnderscore = fullParameterName.indexOf('_');
3192 const QString containerName = fullParameterName.left(firstUnderscore);
3193 const QString parameterName = fullParameterName.mid(firstUnderscore + 1);
3194
3195 std::shared_ptr<cParameterContainer> container = nullptr;
3196 if (containerName == "main")
3197 {
3198 container = gPar;
3199 }
3200 else if (containerName.indexOf("fractal") >= 0)
3201 {
3202 const int index = containerName.rightRef(1).toInt();
3203 if (index < 4)
3204 {
3205 container = gParFractal->at(index);
3206 }
3207 }
3208
3209 if (container)
3210 {
3211 cOneParameter oneParam = container->GetAsOneParameter(parameterName);
3212 oneParam.SetMultiVal(oneParam.GetMultiVal(valueDefault), valueActual);
3213 container->SetFromOneParameter(parameterName, oneParam);
3214 }
3215 }
3216 SynchronizeInterface(gPar, gParFractal, qInterface::write);
3217 }
3218
RandomizeLocalSettings(const QWidget * widget)3219 void cInterface::RandomizeLocalSettings(const QWidget *widget)
3220 {
3221 cRandomizerDialog *randomizer = new cRandomizerDialog();
3222 randomizer->setAttribute(Qt::WA_DeleteOnClose);
3223 randomizer->AssignSourceWidget(widget);
3224 randomizer->show();
3225 }
3226
CreateListOfParametersInWidget(const QWidget * inputWidget)3227 QStringList cInterface::CreateListOfParametersInWidget(const QWidget *inputWidget)
3228 {
3229 QList<QWidget *> listOfWidgets = inputWidget->findChildren<QWidget *>();
3230 QSet<QString> listOfParameters;
3231
3232 foreach (QWidget *widget, listOfWidgets)
3233 {
3234 CommonMyWidgetWrapper *myWidget = dynamic_cast<CommonMyWidgetWrapper *>(widget);
3235 if (myWidget)
3236 {
3237 QString parameterName = myWidget->getFullParameterName();
3238 QString containerName = myWidget->getParameterContainerName();
3239 QString fullParameterName = containerName + "_" + parameterName;
3240 listOfParameters.insert(fullParameterName);
3241 }
3242 }
3243 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
3244 QStringList list(listOfParameters.toList());
3245 #else
3246 QStringList list(listOfParameters.values());
3247 #endif
3248 return list;
3249 }
3250
GlobalStopRequest()3251 void cInterface::GlobalStopRequest()
3252 {
3253 systemData.globalStopRequest = true;
3254 if (!stopRequestPulseTimer)
3255 {
3256 stopRequestPulseTimer = new QTimer(mainWindow); // will be deleted with parent
3257 connect(stopRequestPulseTimer, SIGNAL(timeout()), mainWindow, SLOT(ResetGlobalStopRequest()));
3258 stopRequestPulseTimer->setSingleShot(true);
3259 }
3260
3261 stopRequestPulseTimer->start(1000);
3262 }
3263
ResetGlobalStopRequest()3264 void cInterface::ResetGlobalStopRequest()
3265 {
3266 while (cRenderJob::GetRunningJobCount() > 0)
3267 {
3268 gApplication->processEvents();
3269 }
3270
3271 systemData.globalStopRequest = false;
3272 }
3273
CleanSettings()3274 void cInterface::CleanSettings()
3275 {
3276 if (QMessageBox::Yes
3277 == QMessageBox::question(mainWindow, tr("Cleaning up"),
3278 tr("Do you want to clean up settings?\nIt will take a while"),
3279 QMessageBox::Yes | QMessageBox::No))
3280 {
3281 SynchronizeInterface(gPar, gParFractal, qInterface::read);
3282 gUndo->Store(gPar, gParFractal);
3283 gUndo->Store(gPar, gParFractal);
3284 cSettingsCleaner *cleaner = new cSettingsCleaner(mainWindow);
3285 cleaner->show();
3286 cleaner->runCleaner();
3287 cleaner->exec();
3288 delete cleaner;
3289 SynchronizeInterface(gPar, gParFractal, qInterface::write);
3290 }
3291 }
3292
slotAutoSaveImage(double timeSeconds)3293 void cInterface::slotAutoSaveImage(double timeSeconds)
3294 {
3295 if (timeSeconds > 600)
3296 {
3297 QString filename = systemDirectories.GetImagesFolder() + QDir::separator() + "autosave.png";
3298 SaveImage(filename, ImageFileSave::IMAGE_FILE_TYPE_PNG, gMainInterface->mainImage, nullptr);
3299 mainWindow->ui->statusbar->showMessage(tr("Image auto-saved to %1").arg(filename), 0);
3300 }
3301 }
3302
UpdateMainImagePreview()3303 void cInterface::UpdateMainImagePreview()
3304 {
3305 renderedImage->update();
3306 }
3307
ChangeLightWireframeVisibility(bool enable)3308 void cInterface::ChangeLightWireframeVisibility(bool enable)
3309 {
3310 renderedImage->SetLightsVisibility(enable);
3311 renderedImage->update();
3312 }
3313