1 /**
2  * Mandelbulber v2, a 3D fractal generator       ,=#MKNmMMKmmßMNWy,
3  *                                             ,B" ]L,,p%%%,,,§;, "K
4  * Copyright (C) 2016-20 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)
31  *
32  * Widget which contains UI for rendering engine
33  */
34 
35 #include "dock_rendering_engine.h"
36 
37 #include "ui_dock_rendering_engine.h"
38 
39 #include "dock_fractal.h"
40 #include "dock_image_adjustments.h"
41 #include "dock_navigation.h"
42 
43 #include "src/automated_widgets.hpp"
44 #include "src/initparameters.hpp"
45 #include "src/interface.hpp"
46 #include "src/netrender.hpp"
47 #include "src/projection_3d.hpp"
48 #include "src/render_window.hpp"
49 #include "src/synchronize_interface.hpp"
50 
cDockRenderingEngine(QWidget * parent)51 cDockRenderingEngine::cDockRenderingEngine(QWidget *parent)
52 		: QWidget(parent), ui(new Ui::cDockRenderingEngine)
53 {
54 	ui->setupUi(this);
55 	automatedWidgets = new cAutomatedWidgets(this);
56 	automatedWidgets->ConnectSignalsForSlidersInWindow(this);
57 	ConnectSignals();
58 
59 	ui->groupBox_netrender_client_config->setVisible(false);
60 }
61 
~cDockRenderingEngine()62 cDockRenderingEngine::~cDockRenderingEngine()
63 {
64 	delete ui;
65 }
66 
ConnectSignals() const67 void cDockRenderingEngine::ConnectSignals() const
68 {
69 	connect(ui->checkBox_use_default_bailout, SIGNAL(stateChanged(int)), this,
70 		SLOT(slotChangedCheckBoxUseDefaultBailout(int)));
71 	connect(ui->pushButton_optimization_LQ, SIGNAL(clicked()), this,
72 		SLOT(slotPressedButtonOptimizeForLQ()));
73 	connect(ui->pushButton_optimization_MQ, SIGNAL(clicked()), this,
74 		SLOT(slotPressedButtonOptimizeForMQ()));
75 	connect(ui->pushButton_optimization_HQ, SIGNAL(clicked()), this,
76 		SLOT(slotPressedButtonOptimizeForHQ()));
77 	connect(ui->logedit_detail_level, SIGNAL(returnPressed()), this, SLOT(slotDetailLevelChanged()));
78 	connect(ui->comboBox_delta_DE_method, SIGNAL(currentIndexChanged(int)), this,
79 		SLOT(slotChangedComboDistanceEstimationMethod(int)));
80 
81 	// Limits
82 	connect(ui->bu_bounding_box_to_limit, SIGNAL(clicked()), this,
83 		SLOT(slotPressedButtonSetBoundingBoxAsLimits()));
84 	connect(ui->bu_bounding_box_size_x_up, SIGNAL(clicked()), this,
85 		SLOT(slotPressedButtonBoundingBoxSizeXUp()));
86 	connect(ui->bu_bounding_box_size_x_down, SIGNAL(clicked()), this,
87 		SLOT(slotPressedButtonBoundingBoxSizeXDown()));
88 	connect(ui->bu_bounding_box_size_y_up, SIGNAL(clicked()), this,
89 		SLOT(slotPressedButtonBoundingBoxSizeYUp()));
90 	connect(ui->bu_bounding_box_size_y_down, SIGNAL(clicked()), this,
91 		SLOT(slotPressedButtonBoundingBoxSizeYDown()));
92 	connect(ui->bu_bounding_box_size_z_up, SIGNAL(clicked()), this,
93 		SLOT(slotPressedButtonBoundingBoxSizeZUp()));
94 	connect(ui->bu_bounding_box_size_z_down, SIGNAL(clicked()), this,
95 		SLOT(slotPressedButtonBoundingBoxSizeZDown()));
96 	connect(ui->bu_bounding_box_move_x_neg, SIGNAL(clicked()), this,
97 		SLOT(slotPressedButtonBoundingBoxMoveXNeg()));
98 	connect(ui->bu_bounding_box_move_x_pos, SIGNAL(clicked()), this,
99 		SLOT(slotPressedButtonBoundingBoxMoveXPos()));
100 	connect(ui->bu_bounding_box_move_y_neg, SIGNAL(clicked()), this,
101 		SLOT(slotPressedButtonBoundingBoxMoveYNeg()));
102 	connect(ui->bu_bounding_box_move_y_pos, SIGNAL(clicked()), this,
103 		SLOT(slotPressedButtonBoundingBoxMoveYPos()));
104 	connect(ui->bu_bounding_box_move_z_neg, SIGNAL(clicked()), this,
105 		SLOT(slotPressedButtonBoundingBoxMoveZNeg()));
106 	connect(ui->bu_bounding_box_move_z_pos, SIGNAL(clicked()), this,
107 		SLOT(slotPressedButtonBoundingBoxMoveZPos()));
108 
109 	// NetRender
110 	connect(ui->bu_netrender_connect, SIGNAL(clicked()), this, SLOT(slotNetRenderClientConnect()));
111 	connect(
112 		ui->bu_netrender_disconnect, SIGNAL(clicked()), this, SLOT(slotNetRenderClientDisconnect()));
113 	connect(ui->bu_netrender_start_server, SIGNAL(clicked()), this, SLOT(slotNetRenderServerStart()));
114 	connect(ui->bu_netrender_stop_server, SIGNAL(clicked()), this, SLOT(slotNetRenderServerStop()));
115 	connect(ui->comboBox_netrender_mode, SIGNAL(currentIndexChanged(int)), this,
116 		SLOT(slotNetRenderClientServerChange(int)));
117 	connect(
118 		ui->group_netrender, SIGNAL(toggled(bool)), this, SLOT(slotCheckBoxDisableNetRender(bool)));
119 	connect(ui->bu_netrender_connect, SIGNAL(clicked()), this, SLOT(slotNetRenderClientConnect()));
120 	connect(gNetRender, &cNetRender::NewStatusClient, this,
121 		&cDockRenderingEngine::slotNetRenderStatusClientUpdate);
122 	connect(gNetRender, &cNetRender::NewStatusServer, this,
123 		&cDockRenderingEngine::slotNetRenderStatusServerUpdate);
124 	connect(gNetRender, &cNetRender::ClientsChanged, this,
125 		&cDockRenderingEngine::slotNetRenderClientListUpdate);
126 	connect(gNetRender, &cNetRender::ClientsChangedRow, this,
127 		&cDockRenderingEngine::slotNetRenderClientListUpdateRow);
128 	connect(gNetRender, &cNetRender::ClientsChangedCell, this,
129 		&cDockRenderingEngine::slotNetRenderClientListUpdateCell);
130 
131 	connect(ui->checkBox_connect_detail_level_2, SIGNAL(stateChanged(int)), this,
132 		SIGNAL(stateChangedConnectDetailLevel(int)));
133 
134 	connect(ui->pushButton_calculate_dist_thresh, SIGNAL(clicked()), this,
135 		SLOT(slotCalculateDistanceThreshold()));
136 }
137 
slotNetRenderServerStart() const138 void cDockRenderingEngine::slotNetRenderServerStart() const
139 {
140 	SynchronizeInterfaceWindow(ui->group_netrender, gPar, qInterface::read);
141 	qint32 port = gPar->Get<int>("netrender_server_local_port");
142 	gNetRender->SetServer(port);
143 }
144 
slotNetRenderServerStop()145 void cDockRenderingEngine::slotNetRenderServerStop()
146 {
147 	gNetRender->DeleteServer();
148 }
149 
slotNetRenderClientConnect() const150 void cDockRenderingEngine::slotNetRenderClientConnect() const
151 {
152 	SynchronizeInterfaceWindow(ui->group_netrender, gPar, qInterface::read);
153 	QString address = gPar->Get<QString>("netrender_client_remote_address");
154 	qint32 port = gPar->Get<int>("netrender_client_remote_port");
155 	gNetRender->SetClient(address, port);
156 }
157 
slotNetRenderClientDisconnect()158 void cDockRenderingEngine::slotNetRenderClientDisconnect()
159 {
160 	gNetRender->DeleteClient();
161 }
162 
slotNetRenderClientServerChange(int index) const163 void cDockRenderingEngine::slotNetRenderClientServerChange(int index) const
164 {
165 	ui->groupBox_netrender_client_config->setVisible(index == cNetRender::netRenderDeviceType_CLIENT);
166 	ui->groupBox_netrender_server_config->setVisible(index == cNetRender::netRenderDeviceType_SERVER);
167 }
168 
slotNetRenderClientListUpdate() const169 void cDockRenderingEngine::slotNetRenderClientListUpdate() const
170 {
171 	QTableWidget *table = ui->tableWidget_netrender_connected_clients;
172 
173 	// reset table
174 	if (gNetRender->GetClientCount() == 0)
175 	{
176 		table->clear();
177 		return;
178 	}
179 
180 	// init table
181 	if (table->columnCount() == 0)
182 	{
183 		QStringList header;
184 		header << tr("Name") << tr("Host") << tr("CPUs") << tr("Status") << tr("Items done")
185 					 << tr("Actions");
186 		table->setColumnCount(header.size());
187 		table->setHorizontalHeaderLabels(header);
188 	}
189 
190 	QHeaderView *headers = table->horizontalHeader();
191 	headers->setSectionResizeMode(QHeaderView::ResizeToContents);
192 
193 	// change table
194 	if (table->rowCount() != gNetRender->GetClientCount())
195 	{
196 		table->setRowCount(gNetRender->GetClientCount());
197 	}
198 
199 	// update table
200 	for (int i = 0; i < table->rowCount(); i++)
201 	{
202 		slotNetRenderClientListUpdateRow(i);
203 	}
204 }
205 
slotNetRenderClientListUpdateRow(int i) const206 void cDockRenderingEngine::slotNetRenderClientListUpdateRow(int i) const
207 {
208 	// update row i
209 	QTableWidget *table = ui->tableWidget_netrender_connected_clients;
210 	for (int j = 0; j < table->columnCount(); j++)
211 	{
212 		slotNetRenderClientListUpdateCell(i, j);
213 	}
214 }
215 
slotNetRenderClientListUpdateCell(int i,int j) const216 void cDockRenderingEngine::slotNetRenderClientListUpdateCell(int i, int j) const
217 {
218 	// update element in row i, column j
219 	QTableWidget *table = ui->tableWidget_netrender_connected_clients;
220 
221 	QTableWidgetItem *cell = table->item(i, j);
222 	if (!cell)
223 	{
224 		cell = new QTableWidgetItem;
225 		table->setItem(i, j, cell);
226 	}
227 
228 	switch (j)
229 	{
230 		case 0: cell->setText(gNetRender->GetClient(i).name); break;
231 		case 1: cell->setText(gNetRender->GetClient(i).socket->peerAddress().toString()); break;
232 		case 2: cell->setText(QString::number(gNetRender->GetClient(i).clientWorkerCount)); break;
233 		case 3:
234 		{
235 			QString text = cNetRender::GetStatusText(gNetRender->GetClient(i).status);
236 			QString color = cNetRender::GetStatusColor(gNetRender->GetClient(i).status);
237 
238 			cell->setText(text);
239 			cell->setForeground(QBrush(QColor(color)));
240 			cell->setBackground(QBrush(Qt::white));
241 			break;
242 		}
243 		case 4: cell->setText(QString::number(gNetRender->GetClient(i).itemsRendered)); break;
244 		case 5:
245 		{
246 			QFrame *frame = new QFrame;
247 			QGridLayout *gridLayout = new QGridLayout;
248 			QToolButton *actionKickAndKill = new QToolButton;
249 			actionKickAndKill->setIcon(actionKickAndKill->style()->standardIcon(QStyle::SP_TrashIcon));
250 			actionKickAndKill->setFixedSize(24, 24);
251 			actionKickAndKill->setObjectName(QString::number(i));
252 			gridLayout->setContentsMargins(2, 2, 2, 2);
253 			QObject::connect(
254 				actionKickAndKill, SIGNAL(clicked()), this, SLOT(slotNetRenderKickAndKill()));
255 			gridLayout->addWidget(actionKickAndKill, 0, 0);
256 			gridLayout->setSpacing(0);
257 			frame->setLayout(gridLayout);
258 			table->setCellWidget(i, j, frame);
259 			break;
260 		}
261 		default: break;
262 	}
263 }
264 
slotNetRenderStatusServerUpdate() const265 void cDockRenderingEngine::slotNetRenderStatusServerUpdate() const
266 {
267 	QString text = cNetRender::GetStatusText(gNetRender->GetStatus());
268 	QString color = cNetRender::GetStatusColor(gNetRender->GetStatus());
269 	ui->label_netrender_server_status->setText(text);
270 	ui->label_netrender_server_status->setStyleSheet(
271 				"QLabel { color: " + color + "; font-weight: bold; border: 2px solid darkgray; border-radius: 3px;"
272 						"background: white; text-align: center; qproperty-alignment: AlignCenter;}");
273 
274 	ui->bu_netrender_start_server->setEnabled(!gNetRender->IsServer());
275 	ui->bu_netrender_stop_server->setEnabled(gNetRender->IsServer());
276 }
277 
slotNetRenderStatusClientUpdate() const278 void cDockRenderingEngine::slotNetRenderStatusClientUpdate() const
279 {
280 	QString text = cNetRender::GetStatusText(gNetRender->GetStatus());
281 	QString color = cNetRender::GetStatusColor(gNetRender->GetStatus());
282 	ui->label_netrender_client_connected_server->setText(gNetRender->GetServerName());
283 	ui->label_netrender_client_status->setText(text);
284 	ui->label_netrender_client_status->setStyleSheet(
285 		"QLabel { color: " + color + "; font-weight: bold; border: 2px solid darkgray; border-radius: 3px;"
286 				"background: white; text-align: center; qproperty-alignment: AlignCenter;}");
287 
288 	ui->bu_netrender_connect->setEnabled(!gNetRender->IsClient());
289 	ui->bu_netrender_disconnect->setEnabled(gNetRender->IsClient());
290 	gMainInterface->mainWindow->GetWidgetDockNavigation()->setEnabled(!gNetRender->IsClient());
291 }
292 
slotCheckBoxDisableNetRender(bool on)293 void cDockRenderingEngine::slotCheckBoxDisableNetRender(bool on)
294 {
295 	if (!on)
296 	{
297 		gNetRender->DeleteClient();
298 		gNetRender->DeleteServer();
299 	}
300 }
301 
slotNetRenderKickAndKill()302 void cDockRenderingEngine::slotNetRenderKickAndKill()
303 {
304 	QString buttonName = sender()->objectName();
305 	gNetRender->KickAndKillClient(buttonName.toInt());
306 }
307 
SynchronizeInterfaceDistanceEstimation(std::shared_ptr<cParameterContainer> par) const308 void cDockRenderingEngine::SynchronizeInterfaceDistanceEstimation(
309 	std::shared_ptr<cParameterContainer> par) const
310 {
311 	SynchronizeInterfaceWindow(ui->groupBox_detailLevel, par, qInterface::write);
312 }
313 
ComboDeltaDEFunctionSetEnabled(bool enabled) const314 void cDockRenderingEngine::ComboDeltaDEFunctionSetEnabled(bool enabled) const
315 {
316 	ui->comboBox_delta_DE_function->setEnabled(enabled);
317 }
318 
ComboDeltaDEMethodCurrentIndex() const319 int cDockRenderingEngine::ComboDeltaDEMethodCurrentIndex() const
320 {
321 	return ui->comboBox_delta_DE_method->currentIndex();
322 }
323 
slotChangedComboDistanceEstimationMethod(int index) const324 void cDockRenderingEngine::slotChangedComboDistanceEstimationMethod(int index) const
325 {
326 	Q_UNUSED(index);
327 	// ui->comboBox_delta_DE_function->setEnabled(
328 	//	gMainInterface->mainWindow->GetWidgetDockFractal()->AreHybridFractalsEnabled()
329 	//	|| index == int(fractal::forceDeltaDEMethod));
330 }
331 
CheckboxConnectDetailLevelSetCheckState(Qt::CheckState state) const332 void cDockRenderingEngine::CheckboxConnectDetailLevelSetCheckState(Qt::CheckState state) const
333 {
334 	ui->checkBox_connect_detail_level_2->setCheckState(state);
335 }
336 
UpdateLabelWrongDEPercentage(const QString & text) const337 void cDockRenderingEngine::UpdateLabelWrongDEPercentage(const QString &text) const
338 {
339 	ui->label_wrong_DE_percentage->setText(text);
340 }
341 
UpdateLabelUsedDistanceEstimation(const QString & text) const342 void cDockRenderingEngine::UpdateLabelUsedDistanceEstimation(const QString &text) const
343 {
344 	ui->label_used_distance_estimation->setText(text);
345 }
346 
slotChangedCheckBoxUseDefaultBailout(int state) const347 void cDockRenderingEngine::slotChangedCheckBoxUseDefaultBailout(int state) const
348 {
349 	ui->logedit_bailout->setEnabled(!state);
350 }
351 
slotDetailLevelChanged()352 void cDockRenderingEngine::slotDetailLevelChanged()
353 {
354 	if (gMainInterface->mainWindow->GetWidgetDockImageAdjustments()->IsConnectDetailLevelEnabled())
355 	{
356 		gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::read);
357 		gMainInterface->lockedDetailLevel = gPar->Get<double>("detail_level");
358 		gMainInterface->lockedImageResolution =
359 			CVector2<int>(gPar->Get<int>("image_width"), gPar->Get<int>("image_height"));
360 	}
361 }
362 
slotPressedButtonOptimizeForLQ()363 void cDockRenderingEngine::slotPressedButtonOptimizeForLQ()
364 {
365 	gMainInterface->OptimizeStepFactor(1.0);
366 }
367 
slotPressedButtonOptimizeForMQ()368 void cDockRenderingEngine::slotPressedButtonOptimizeForMQ()
369 {
370 	gMainInterface->OptimizeStepFactor(0.1);
371 }
slotPressedButtonOptimizeForHQ()372 void cDockRenderingEngine::slotPressedButtonOptimizeForHQ()
373 {
374 	gMainInterface->OptimizeStepFactor(0.01);
375 }
slotPressedButtonSetBoundingBoxAsLimits()376 void cDockRenderingEngine::slotPressedButtonSetBoundingBoxAsLimits()
377 {
378 	gMainInterface->SetBoundingBoxAsLimitsTotal();
379 }
slotPressedButtonBoundingBoxSizeXUp()380 void cDockRenderingEngine::slotPressedButtonBoundingBoxSizeXUp()
381 {
382 	gMainInterface->BoundingBoxMove('x', 0.05, 0.05);
383 }
slotPressedButtonBoundingBoxSizeXDown()384 void cDockRenderingEngine::slotPressedButtonBoundingBoxSizeXDown()
385 {
386 	gMainInterface->BoundingBoxMove('x', -0.05, -0.05);
387 }
slotPressedButtonBoundingBoxSizeYUp()388 void cDockRenderingEngine::slotPressedButtonBoundingBoxSizeYUp()
389 {
390 	gMainInterface->BoundingBoxMove('y', 0.05, 0.05);
391 }
slotPressedButtonBoundingBoxSizeYDown()392 void cDockRenderingEngine::slotPressedButtonBoundingBoxSizeYDown()
393 {
394 	gMainInterface->BoundingBoxMove('y', -0.05, -0.05);
395 }
slotPressedButtonBoundingBoxSizeZUp()396 void cDockRenderingEngine::slotPressedButtonBoundingBoxSizeZUp()
397 {
398 	gMainInterface->BoundingBoxMove('z', 0.05, 0.05);
399 }
slotPressedButtonBoundingBoxSizeZDown()400 void cDockRenderingEngine::slotPressedButtonBoundingBoxSizeZDown()
401 {
402 	gMainInterface->BoundingBoxMove('z', -0.05, -0.05);
403 }
slotPressedButtonBoundingBoxMoveXNeg()404 void cDockRenderingEngine::slotPressedButtonBoundingBoxMoveXNeg()
405 {
406 	gMainInterface->BoundingBoxMove('x', -0.05, 0.05);
407 }
slotPressedButtonBoundingBoxMoveXPos()408 void cDockRenderingEngine::slotPressedButtonBoundingBoxMoveXPos()
409 {
410 	gMainInterface->BoundingBoxMove('x', 0.05, -0.05);
411 }
slotPressedButtonBoundingBoxMoveYNeg()412 void cDockRenderingEngine::slotPressedButtonBoundingBoxMoveYNeg()
413 {
414 	gMainInterface->BoundingBoxMove('y', -0.05, 0.05);
415 }
slotPressedButtonBoundingBoxMoveYPos()416 void cDockRenderingEngine::slotPressedButtonBoundingBoxMoveYPos()
417 {
418 	gMainInterface->BoundingBoxMove('y', 0.05, -0.05);
419 }
slotPressedButtonBoundingBoxMoveZNeg()420 void cDockRenderingEngine::slotPressedButtonBoundingBoxMoveZNeg()
421 {
422 	gMainInterface->BoundingBoxMove('z', -0.05, 0.05);
423 }
slotPressedButtonBoundingBoxMoveZPos()424 void cDockRenderingEngine::slotPressedButtonBoundingBoxMoveZPos()
425 {
426 	gMainInterface->BoundingBoxMove('z', 0.05, -0.05);
427 }
428 
slotCalculateDistanceThreshold()429 void cDockRenderingEngine::slotCalculateDistanceThreshold()
430 {
431 	gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::read);
432 	double distance = gMainInterface->GetDistanceForPoint(gPar->Get<CVector3>("camera"));
433 	double detailLevel = gPar->Get<double>("detail_level");
434 	double imageWidth = gPar->Get<int>("image_width");
435 	params::enumPerspectiveType perspectiveType =
436 		params::enumPerspectiveType(gPar->Get<int>("perspective_type"));
437 	double fov = CalcFOV(gPar->Get<int>("fov"), perspectiveType);
438 	double distThresh = fov / detailLevel / imageWidth * distance * 10.0;
439 	gPar->Set("DE_thresh", distThresh);
440 	gMainInterface->SynchronizeInterface(gPar, gParFractal, qInterface::write);
441 }
442