1 /**************************************************************************/
2 /* Copyright 2012 Tim Day */
3 /* */
4 /* This file is part of Evolvotron */
5 /* */
6 /* Evolvotron is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* Evolvotron is distributed in the hope that it will be useful, */
12 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
13 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
14 /* GNU General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU General Public License */
17 /* along with Evolvotron. If not, see <http://www.gnu.org/licenses/>. */
18 /**************************************************************************/
19
20 /*! \file
21 \brief Implementation of class EvolvotronMain.
22 \todo Eliminate need to include function.h (and instantiate lots of stuff) by moving more into function_node.h/.cpp
23 */
24
25 #include "evolvotron_main.h"
26
27 #include "dialog_about.h"
28 #include "dialog_help.h"
29 #include "dialog_mutation_parameters.h"
30 #include "dialog_render_parameters.h"
31 #include "dialog_functions.h"
32 #include "dialog_favourite.h"
33 #include "function_node.h"
34 #include "function_post_transform.h"
35 #include "function_pre_transform.h"
36 #include "function_top.h"
37
purge()38 void EvolvotronMain::History::purge()
39 {
40 if (_archive.size()>0) _archive.pop_back();
41 }
42
History(EvolvotronMain * m)43 EvolvotronMain::History::History(EvolvotronMain* m)
44 :_main(m)
45 ,max_slots(32)
46 {
47 // Don't call _main->set_undoable because menus probably haven't been constructed yet.
48 }
49
~History()50 EvolvotronMain::History::~History()
51 {}
52
log_status() const53 void EvolvotronMain::History::log_status() const
54 {
55 std::clog << "[History: " << _archive.size() << " records (";
56 for (Archive::const_iterator it=_archive.begin();it!=_archive.end();it++)
57 std::clog << (it!=_archive.begin() ? "," : "") << (*it).second.size();
58 std::clog << ")]\n";
59 }
60
goodbye(MutatableImageDisplay * display)61 void EvolvotronMain::History::goodbye(MutatableImageDisplay* display)
62 {
63 // First pass to delete any individual items for that display.
64 for (Archive::iterator it=_archive.begin();it!=_archive.end();it++)
65 (*it).second.erase(display);
66
67 // Second pass to delete any undo items which are now empty
68 Archive::iterator it=_archive.begin();
69 while (it!=_archive.end())
70 {
71 if ((*it).second.empty()) it=_archive.erase(it);
72 it++;
73 }
74
75 // Set menu label again in case we've changed the topmost item
76 const std::string action_name(_archive.empty() ? "" : _archive.front().first);
77 _main->set_undoable(undoable(),action_name);
78 }
79
replacing(MutatableImageDisplay * display)80 void EvolvotronMain::History::replacing(MutatableImageDisplay* display)
81 {
82 if (_archive.size()==0)
83 {
84 begin_action("");
85 }
86
87 const boost::shared_ptr<const MutatableImage> image_function=display->image_function();
88
89 if (image_function.get())
90 {
91 const boost::shared_ptr<const MutatableImage> saved_image_function(image_function->deepclone(image_function->locked()));
92 _archive.front().second.insert(std::make_pair(display,saved_image_function));
93 }
94 }
95
96 /*! Only creates a new slot for display-image pairs if the current top one (if any) isn't empty.
97 */
begin_action(const std::string & action_name)98 void EvolvotronMain::History::begin_action(const std::string& action_name)
99 {
100 if (_archive.size()==0 || _archive.front().second.size()!=0)
101 {
102 _archive.push_front(ArchiveRecord());
103
104 assert(_archive.front().second.size()==0);
105 }
106
107 _archive.front().first=action_name;
108
109 while (_archive.size()>max_slots)
110 {
111 purge();
112 }
113 }
114
end_action()115 void EvolvotronMain::History::end_action()
116 {
117 const std::string action_name(_archive.empty() ? "" : _archive.front().first);
118 _main->set_undoable(undoable(),action_name);
119
120 log_status();
121 }
122
undoable()123 bool EvolvotronMain::History::undoable()
124 {
125 if (_archive.size()==0)
126 {
127 return false;
128 }
129 else if (_archive.front().second.size()==0)
130 {
131 _archive.pop_front();
132 return undoable();
133 }
134 else
135 {
136 return true;
137 }
138 }
139
undo()140 void EvolvotronMain::History::undo()
141 {
142 if (_archive.size()==0)
143 {
144 // Shouldn't ever see this if Undo menu item is correctly greyed out.
145 QMessageBox::warning(_main,"Evolvotron","Sorry, cannot undo any further");
146 }
147 else if (_archive.front().second.size()==0)
148 {
149 _archive.pop_front();
150 undo();
151 }
152 else
153 {
154 for (ArchiveRecordEntries::iterator it=_archive.front().second.begin();
155 it!=_archive.front().second.end();
156 it++
157 )
158 {
159 _main->restore((*it).first,(*it).second,_archive.size()>1);
160 }
161 _archive.pop_front();
162 }
163
164 const std::string action_name(_archive.empty() ? "" : _archive.front().first);
165 _main->set_undoable(undoable(),action_name);
166 }
167
last_spawned_image(const boost::shared_ptr<const MutatableImage> & image,SpawnMemberFn method)168 void EvolvotronMain::last_spawned_image(const boost::shared_ptr<const MutatableImage>& image,SpawnMemberFn method)
169 {
170 _last_spawned_image=image;
171 _last_spawn_method=method;
172 }
173
174 /*! Constructor sets up GUI components and fires up QTimer.
175 Initialises mutation parameters using time, so different every time.
176 */
EvolvotronMain(QWidget * parent,const QSize & grid_size,uint frames,uint framerate,uint n_threads,bool separate_farm_for_enlargements,int niceness_grid,int niceness_enlargements,bool start_fullscreen,bool start_menuhidden,bool autocool,bool jitter,uint multisample_level,bool function_debug_mode,bool linear_zsweep,bool spheremap,const std::vector<std::string> & startup_filenames,bool startup_shuffle)177 EvolvotronMain::EvolvotronMain
178 (
179 QWidget* parent,
180 const QSize& grid_size,
181 uint frames,
182 uint framerate,
183 uint n_threads,
184 bool separate_farm_for_enlargements,
185 int niceness_grid,
186 int niceness_enlargements,
187 bool start_fullscreen,
188 bool start_menuhidden,
189 bool autocool,
190 bool jitter,
191 uint multisample_level,
192 bool function_debug_mode,
193 bool linear_zsweep,
194 bool spheremap,
195 const std::vector<std::string>& startup_filenames,
196 bool startup_shuffle
197 )
198 :QMainWindow(parent)
199 ,_history(new EvolvotronMain::History(this))
200 ,_linear_zsweep(linear_zsweep)
201 ,_spheremap(spheremap)
202 ,_startup_filenames(startup_filenames)
203 ,_startup_shuffle(startup_shuffle)
204 ,_mutation_parameters(time(0),autocool,function_debug_mode,this)
205 ,_render_parameters(jitter,multisample_level,this)
206 ,_statusbar_tasks_main(0)
207 ,_statusbar_tasks_enlargement(0)
208 ,_last_spawn_method(&EvolvotronMain::spawn_normal)
209 {
210 setAttribute(Qt::WA_DeleteOnClose,true);
211 setAttribute(Qt::WA_QuitOnClose,true);
212
213 setMinimumSize(640,480);
214
215 // Need to create this first or DialogMutationParameters might cause one to be created too.
216 _statusbar=new QStatusBar;
217 _statusbar->setSizeGripEnabled(true);
218 setStatusBar(_statusbar);
219
220 _statusbar->addWidget(_statusbar_tasks_label=new QLabel("Ready"));
221
222 _dialog_about=new DialogAbout(this,n_threads,separate_farm_for_enlargements);
223 _dialog_help_short=new DialogHelp(this,false);
224 _dialog_help_long=new DialogHelp(this,true);
225
226 _dialog_mutation_parameters=new DialogMutationParameters(this,&_mutation_parameters);
227
228 _dialog_render_parameters=new DialogRenderParameters(this,&_render_parameters);
229
230 _dialog_functions=new DialogFunctions(this,&_mutation_parameters);
231
232 _dialog_favourite=new DialogFavourite(this);
233
234 _popupmenu_file=menuBar()->addMenu("&File");
235 _popupmenu_file->addAction("Reset (Reset mutation parameters, clear locks)",this,SLOT(reset_cold()),QKeySequence("r"));
236 _popupmenu_file->addAction("Restart (Preserve mutation parameters and locks)",this,SLOT(reset_warm()),QKeySequence("t"));
237 _popupmenu_file->addAction("Remix (Randomize function weights and restart)",this,SLOT(reset_randomized()),QKeySequence("x"));
238 _popupmenu_file->addSeparator();
239 _popupmenu_file->addAction("Quit",qApp,SLOT(quit()),QKeySequence("q"));
240
241 _popupmenu_edit=menuBar()->addMenu("&Edit");
242 _popupmenu_edit_undo_action=_popupmenu_edit->addAction("Undo",this,SLOT(undo()),QKeySequence("u"));
243 _popupmenu_edit_undo_action->setEnabled(false);
244 _popupmenu_edit->addSeparator();
245 _popupmenu_edit->addAction("Simplify all functions",this,SLOT(simplify_constants()));
246
247 _popupmenu_settings=menuBar()->addMenu("Se&ttings");
248 _popupmenu_settings->addAction("Mutation parameters...",_dialog_mutation_parameters,SLOT(show()));
249 _popupmenu_settings->addAction("Function weightings...",_dialog_functions,SLOT(show()));
250 _popupmenu_settings->addAction("Favourite function...",_dialog_favourite,SLOT(show()));
251
252 _popupmenu_settings->addSeparator();
253
254 _popupmenu_settings->addAction("Render parameters...",_dialog_render_parameters,SLOT(show()));
255
256 _popupmenu_settings->addSeparator();
257
258 _menu_action_fullscreen=_popupmenu_settings->addAction("Fullscreen",this,SLOT(toggle_fullscreen()),QKeySequence("f"));
259 _menu_action_fullscreen->setCheckable(true);
260 _menu_action_fullscreen->setChecked(start_fullscreen);
261 _menu_action_hide_menu=_popupmenu_settings->addAction("Hide menu and statusbar",this,SLOT(toggle_hide_menu()),QKeySequence("m"));
262 _menu_action_hide_menu->setCheckable(true);
263 _menu_action_hide_menu->setChecked(start_menuhidden);
264
265 //! This doesn't seem to do anything (supposed to push help menu over to far end ?)
266 menuBar()->addSeparator();
267
268 _popupmenu_help=menuBar()->addMenu("&Help");
269 _popupmenu_help->addAction("Quick Reference",_dialog_help_short,SLOT(show()));
270 _popupmenu_help->addAction("User Manual",_dialog_help_long,SLOT(show()));
271 _popupmenu_help->addSeparator();
272 _popupmenu_help->addAction("About",_dialog_about,SLOT(show()));
273
274 _checkbox_autocool_enable=new QCheckBox("Autocool");
275 _checkbox_autocool_enable->setToolTip("Autocooling gradually reduces the chance and magnitude of mutations with time.");
276 _label_autocool_enable=new QLabel(""); // Used to display generation count
277 _button_autocool_reheat=new QPushButton("Reheat");
278 _button_autocool_reheat->setToolTip("Reheat restarts the autocooling generation count, restoring the full strength of mutations.");
279
280 connect(_checkbox_autocool_enable,SIGNAL(stateChanged(int)),_dialog_mutation_parameters,SLOT(changed_autocool_enable(int)));
281 connect(_button_autocool_reheat,SIGNAL(clicked()),_dialog_mutation_parameters,SLOT(reheat()));
282
283 _statusbar->addPermanentWidget(_checkbox_autocool_enable);
284 _statusbar->addPermanentWidget(_label_autocool_enable);
285 _statusbar->addPermanentWidget(_button_autocool_reheat);
286
287 connect(
288 &_render_parameters,SIGNAL(changed()),
289 this,SLOT(render_parameters_changed())
290 );
291
292 connect(
293 &_mutation_parameters,SIGNAL(changed()),
294 this,SLOT(mutation_parameters_changed())
295 );
296
297
298 _farm[0]=std::unique_ptr<MutatableImageComputerFarm>(new MutatableImageComputerFarm(n_threads,niceness_grid));
299 if (separate_farm_for_enlargements)
300 {
301 _farm[1]=std::unique_ptr<MutatableImageComputerFarm>(new MutatableImageComputerFarm(n_threads,niceness_enlargements));
302 }
303
304 _grid=new QWidget;
305 QGridLayout*const grid_layout=new QGridLayout;
306 _grid->setLayout(grid_layout);
307 setCentralWidget(_grid);
308
309 //! \todo frames and framerate should be retained and modifiable from the GUI
310 for (int r=0;r<grid_size.height();r++)
311 for (int c=0;c<grid_size.width();c++)
312 {
313 MutatableImageDisplay*const d=new MutatableImageDisplay(this,true,false,QSize(0,0),frames,framerate);
314 grid_layout->addWidget(d,r,c);
315 displays().push_back(d);
316 }
317
318 _timer=new QTimer(this);
319 connect(
320 _timer,SIGNAL(timeout()),
321 this, SLOT(tick())
322 );
323 // Run tick() at 100Hz
324 _timer->start(10);
325
326 if (start_fullscreen)
327 {
328 showFullScreen();
329 }
330
331 if (start_menuhidden)
332 {
333 menuBar()->hide();
334 statusBar()->hide();
335 }
336 }
337
338 /*! If this is being destroyed then the whole application is going down.
339 Could be ordering issues with the display destructors though.
340 */
~EvolvotronMain()341 EvolvotronMain::~EvolvotronMain()
342 {
343 std::clog << "Evolvotron shut down begun...\n";
344
345 // Orphan any displays which outlived us (and clear their images) (look out: shutdown order is Qt-determined)
346 std::clog << "(There are " << _known_displays.size() << " displays remaining)\n";
347 for (std::set<MutatableImageDisplay*>::const_iterator it=_known_displays.begin();it!=_known_displays.end();it++)
348 {
349 (*it)->image_function(boost::shared_ptr<const MutatableImage>(),true);
350 (*it)->main(0);
351 }
352
353 std::clog << "...cleared displays, deleting farm...\n";
354
355 // Shut down the compute farms
356 _farm[0].reset();
357 _farm[1].reset();
358
359 std::clog << "...deleted farm, deleting history...\n";
360
361 // Clean up records.
362 _last_spawned_image.reset();
363 _history.reset();
364
365 std::clog << "...deleted history\n";
366
367 std::clog << "...completed Evolvotron shutdown\n";
368 }
369
favourite_function(const std::string & f)370 bool EvolvotronMain::favourite_function(const std::string& f)
371 {
372 return _dialog_favourite->favourite_function(f);
373 }
374
favourite_function_unwrapped(bool v)375 void EvolvotronMain::favourite_function_unwrapped(bool v)
376 {
377 _dialog_favourite->favourite_function_unwrapped(v);
378 }
379
spawn_normal(const boost::shared_ptr<const MutatableImage> & image_function,MutatableImageDisplay * display,bool one_of_many)380 void EvolvotronMain::spawn_normal(const boost::shared_ptr<const MutatableImage>& image_function,MutatableImageDisplay* display,bool one_of_many)
381 {
382 boost::shared_ptr<const MutatableImage> new_image_function;
383
384 do
385 {
386 new_image_function=image_function->mutated(mutation_parameters());
387 }
388 while (new_image_function->is_constant());
389
390 history().replacing(display);
391 display->image_function(new_image_function,one_of_many);
392 }
393
spawn_recoloured(const boost::shared_ptr<const MutatableImage> & image_function,MutatableImageDisplay * display,bool one_of_many)394 void EvolvotronMain::spawn_recoloured(const boost::shared_ptr<const MutatableImage>& image_function,MutatableImageDisplay* display,bool one_of_many)
395 {
396 std::unique_ptr<FunctionTop> new_root(image_function->top().typed_deepclone());
397
398 new_root->reset_posttransform_parameters(mutation_parameters());
399 history().replacing(display);
400 boost::shared_ptr<const MutatableImage> it(new MutatableImage(new_root,image_function->sinusoidal_z(),image_function->spheremap(),false));
401 display->image_function(it,one_of_many);
402 }
403
spawn_warped(const boost::shared_ptr<const MutatableImage> & image_function,MutatableImageDisplay * display,bool one_of_many)404 void EvolvotronMain::spawn_warped(const boost::shared_ptr<const MutatableImage>& image_function,MutatableImageDisplay* display,bool one_of_many)
405 {
406 std::unique_ptr<FunctionTop> new_root=std::unique_ptr<FunctionTop>(image_function->top().typed_deepclone());
407
408 // Get the transform from whatever factory is currently set
409 const Transform transform(transform_factory()(mutation_parameters().rng01()));
410
411 new_root->concatenate_pretransform_on_right(transform);
412 history().replacing(display);
413 boost::shared_ptr<const MutatableImage> it(new MutatableImage(new_root,image_function->sinusoidal_z(),image_function->spheremap(),false));
414 display->image_function(it,one_of_many);
415 }
416
restore(MutatableImageDisplay * display,const boost::shared_ptr<const MutatableImage> & image_function,bool one_of_many)417 void EvolvotronMain::restore(MutatableImageDisplay* display,const boost::shared_ptr<const MutatableImage>& image_function,bool one_of_many)
418 {
419 if (is_known(display)) display->image_function(image_function,one_of_many);
420 }
421
set_undoable(bool v,const std::string & action_name)422 void EvolvotronMain::set_undoable(bool v,const std::string& action_name)
423 {
424 _popupmenu_edit_undo_action->setText(QString(("Undo "+action_name).c_str()));
425 _popupmenu_edit_undo_action->setEnabled(v);
426 }
427
respawn(MutatableImageDisplay * display)428 void EvolvotronMain::respawn(MutatableImageDisplay* display)
429 {
430 if (display->locked())
431 {
432 QMessageBox::warning(this,"Evolvotron","Cannot respawn a locked image.\nUnlock and try again.");
433 }
434 else
435 {
436 history().begin_action("respawn");
437
438 if (last_spawned_image()==0)
439 {
440 reset(display);
441 }
442 else
443 {
444 (this->*last_spawn_method())(last_spawned_image(),display,false);
445 }
446
447 history().end_action();
448 }
449 }
450
spawn_all(MutatableImageDisplay * spawning_display,SpawnMemberFn method,const std::string & action_name)451 void EvolvotronMain::spawn_all(MutatableImageDisplay* spawning_display,SpawnMemberFn method,const std::string& action_name)
452 {
453 // Spawn potentially a bit sluggish so set the hourglass cursor.
454 QApplication::setOverrideCursor(Qt::WaitCursor);
455
456 history().begin_action(action_name);
457
458 // Issue new images (except to locked displays and to originator)
459 // This will cause them to abort any running tasks
460 const boost::shared_ptr<const MutatableImage> spawning_image_function(spawning_display->image_function());
461
462 last_spawned_image(spawning_image_function,method);
463
464 for (std::vector<MutatableImageDisplay*>::iterator it=displays().begin();it!=displays().end();it++)
465 {
466 if ((*it)!=spawning_display && !(*it)->locked())
467 {
468 (this->*method)(spawning_image_function,(*it),true);
469 }
470 }
471
472 history().end_action();
473
474 _mutation_parameters.autocool_generations_increment();
475
476 QApplication::restoreOverrideCursor();
477 }
478
479
480 /*! If one of our sub displays has spawned, distribute a mutated copy of its image to the other non-locked images
481 in the mutation grid.
482 */
spawn_normal(MutatableImageDisplay * spawning_display)483 void EvolvotronMain::spawn_normal(MutatableImageDisplay* spawning_display)
484 {
485 spawn_all(
486 spawning_display,
487 &EvolvotronMain::spawn_normal,
488 "spawn"
489 );
490 }
491
492 /*! This is the similar to spawn_normal, except images ARE NOT MUTATED after deepclone and have a final transform applied to change their colour.
493 */
spawn_recoloured(MutatableImageDisplay * spawning_display)494 void EvolvotronMain::spawn_recoloured(MutatableImageDisplay* spawning_display)
495 {
496 spawn_all(
497 spawning_display,
498 &EvolvotronMain::spawn_recoloured,
499 "spawn recoloured"
500 );
501 }
502
503 /*! This is the similar to spawn_normal, except images ARE NOT MUTATED after deepclone
504 and have an initial transform (obtained from the supplied TransformFactory) applied to spatially warp them.
505 */
spawn_warped(MutatableImageDisplay * spawning_display,const TransformFactory & tfactory)506 void EvolvotronMain::spawn_warped(MutatableImageDisplay* spawning_display,const TransformFactory& tfactory)
507 {
508 transform_factory(tfactory);
509 spawn_all(
510 spawning_display,
511 &EvolvotronMain::spawn_warped,
512 "spawn warped"
513 );
514 }
515
hello(MutatableImageDisplay * disp)516 void EvolvotronMain::hello(MutatableImageDisplay* disp)
517 {
518 _known_displays.insert(disp);
519 }
520
goodbye(MutatableImageDisplay * disp)521 void EvolvotronMain::goodbye(MutatableImageDisplay* disp)
522 {
523 _history->goodbye(disp);
524 _known_displays.erase(disp);
525 }
526
is_known(MutatableImageDisplay * disp) const527 bool EvolvotronMain::is_known(MutatableImageDisplay* disp) const
528 {
529 return (_known_displays.find(disp)!=_known_displays.end());
530 }
531
list_known(std::ostream & out) const532 void EvolvotronMain::list_known(std::ostream& out) const
533 {
534 for (std::set<MutatableImageDisplay*>::const_iterator it=_known_displays.begin();it!=_known_displays.end();it++)
535 {
536 out << (*it) << " ";
537 }
538 out << "\n";
539 }
540
541 /*! Periodically report number of remaining compute tasks and check farm's done queue for completed tasks.
542 */
tick()543 void EvolvotronMain::tick()
544 {
545 const uint tasks_main=_farm[0]->tasks();
546 const uint tasks_enlargement=(_farm[1].get() ? _farm[1]->tasks() : 0);
547 if (tasks_main!=_statusbar_tasks_main || tasks_enlargement!=_statusbar_tasks_enlargement)
548 {
549 std::ostringstream msg;
550 msg << "";
551
552 if (tasks_main+tasks_enlargement==0)
553 {
554 msg << "Ready";
555 }
556 else
557 {
558 msg << tasks_main;
559 if (tasks_enlargement)
560 {
561 msg << "+" << tasks_enlargement;
562 }
563 msg << " tasks remaining";
564 }
565
566 _statusbar_tasks_label->setText(msg.str().c_str());
567 _statusbar_tasks_main=tasks_main;
568 _statusbar_tasks_enlargement=tasks_enlargement;
569 }
570
571 boost::shared_ptr<MutatableImageComputerTask> task;
572
573 // If there are aborted jobs in the todo queue
574 // shift them straight over to done queue so the compute threads don't have to worry about them.
575 _farm[0]->fasttrack_aborted();
576 if (_farm[1].get()) _farm[1]->fasttrack_aborted();
577
578 QTime watchdog;
579 watchdog.start();
580
581 for (int which_farm=0;which_farm<(_farm[1].get() ? 2 : 1);which_farm++)
582 {
583 while ((task=_farm[which_farm]->pop_done())!=0)
584 {
585 if (is_known(task->display()))
586 {
587 task->display()->deliver(task);
588 }
589 else
590 {
591 // If we don't know who owns it we just have to trash it
592 // (probably a top level window which was closed with incomplete tasks).
593 task.reset();
594 }
595
596 // Timeout in case we're being swamped by incoming tasks (maintain app responsiveness).
597 if (watchdog.elapsed()>20)
598 break;
599 }
600 }
601 }
602
keyPressEvent(QKeyEvent * e)603 void EvolvotronMain::keyPressEvent(QKeyEvent* e)
604 {
605 if (e->key()==Qt::Key_Escape)
606 {
607 // Esc key used to back out of menu hide and full screen mode
608 // Might rescue a few users who have got into those states accidentally
609 showNormal();
610 menuBar()->show();
611 statusBar()->show();
612 _menu_action_fullscreen->setChecked(false);
613 _menu_action_hide_menu->setChecked(false);
614 }
615 else if (e->key()==Qt::Key_Z && !(e->modifiers()^Qt::ControlModifier))
616 {
617 //Ctrl-Z does an undo
618 undo();
619 }
620 else
621 {
622 // Perhaps it's for someone else
623 e->ignore();
624 }
625 }
626
627
toggle_fullscreen()628 void EvolvotronMain::toggle_fullscreen()
629 {
630 if (isFullScreen())
631 {
632 showNormal();
633 _menu_action_fullscreen->setChecked(false);
634 }
635 else
636 {
637 showFullScreen();
638 _menu_action_fullscreen->setChecked(true);
639 }
640 }
641
toggle_hide_menu()642 void EvolvotronMain::toggle_hide_menu()
643 {
644 if (menuBar()->isHidden())
645 {
646 menuBar()->show();
647 _menu_action_hide_menu->setChecked(false);
648 }
649 else if (menuBar()->isVisible())
650 {
651 menuBar()->hide();
652 _menu_action_hide_menu->setChecked(true);
653 }
654
655 if (statusBar()->isHidden())
656 statusBar()->show();
657 else if (statusBar()->isVisible())
658 statusBar()->hide();
659 }
660
661 /*! Set up an initial random image in the specified display.
662 If a favourite function was specified then we use that as the top level node.
663 */
reset(MutatableImageDisplay * display)664 void EvolvotronMain::reset(MutatableImageDisplay* display)
665 {
666 std::unique_ptr<FunctionTop> root;
667 if (_dialog_favourite->favourite_function().empty())
668 {
669 root=std::unique_ptr<FunctionTop>(FunctionTop::initial(mutation_parameters()));
670 }
671 else
672 {
673 root=std::unique_ptr<FunctionTop>
674 (
675 FunctionTop::initial
676 (
677 mutation_parameters(),
678 mutation_parameters().function_registry().lookup(_dialog_favourite->favourite_function()),
679 _dialog_favourite->favourite_function_unwrapped()
680 )
681 );
682 }
683
684 history().replacing(display);
685 const boost::shared_ptr<const MutatableImage> image_function(new MutatableImage(root,!_linear_zsweep,_spheremap,false));
686 display->image_function(image_function,true);
687 }
688
undo()689 void EvolvotronMain::undo()
690 {
691 history().undo();
692 }
693
simplify_constants()694 void EvolvotronMain::simplify_constants()
695 {
696 history().begin_action("simplify all");
697 uint nodes_eliminated=0;
698 for (std::vector<MutatableImageDisplay*>::iterator it=_displays.begin();it!=_displays.end();it++)
699 {
700 nodes_eliminated+=(*it)->simplify_constants(false);
701 }
702 history().end_action();
703 std::stringstream msg;
704 msg << "Eliminated " << nodes_eliminated << " redundant function nodes\n";
705 QMessageBox::information(this,"Evolvotron",msg.str().c_str(),QMessageBox::Ok);
706 }
707
708 /*! Reset each image in the grid, and the mutation parameters.
709 */
reset(bool reset_mutation_parameters,bool clear_locks)710 void EvolvotronMain::reset(bool reset_mutation_parameters,bool clear_locks)
711 {
712 history().begin_action("reset/restart");
713
714 if (reset_mutation_parameters)
715 {
716 // Invoking reset on the 1st dialog actually resets the parameters
717 _dialog_mutation_parameters->reset();
718 // This one just serves to setup the function dialog from the now reset parameters
719 _dialog_functions->setup_from_mutation_parameters();
720 }
721 else
722 {
723 // Seems odd if we don't restart the count.
724 _mutation_parameters.autocool_generations(0);
725 }
726
727 for (size_t i=0;i<displays().size();++i)
728 {
729 if (clear_locks)
730 displays()[i]->lock(false,false); // lock method mustn't make it's own history recording
731 }
732
733 if (_startup_shuffle) {
734 std::random_shuffle(_startup_filenames.begin(),_startup_filenames.end());
735 }
736
737 for (size_t i=0;i<displays().size();++i) {
738 if (!displays()[i]->locked()) {
739 if (i<_startup_filenames.size())
740 displays()[i]->load_function_file(_startup_filenames[i].c_str());
741 else
742 reset(displays()[i]);
743 }
744 }
745
746 last_spawned_image(boost::shared_ptr<const MutatableImage>(),&EvolvotronMain::spawn_normal);
747
748 history().end_action();
749 }
750
reset_randomized()751 void EvolvotronMain::reset_randomized()
752 {
753 _mutation_parameters.randomize_function_weightings_for_classifications(static_cast<uint>(-1));
754 reset(false,false);
755 }
756
reset_warm()757 void EvolvotronMain::reset_warm()
758 {
759 reset(false,false);
760 }
761
reset_cold()762 void EvolvotronMain::reset_cold()
763 {
764 reset(true,true);
765 }
766
mutation_parameters_changed()767 void EvolvotronMain::mutation_parameters_changed()
768 {
769 _checkbox_autocool_enable->setChecked(_mutation_parameters.autocool_enable());
770 if (_mutation_parameters.autocool_enable())
771 {
772 _label_autocool_enable->setText(QString("Generations:")+QString::number(_mutation_parameters.autocool_generations()));
773 _label_autocool_enable->show();
774
775 if (_mutation_parameters.autocool_generations()>0) _button_autocool_reheat->show();
776 else _button_autocool_reheat->hide();
777
778 }
779 else
780 {
781 _label_autocool_enable->hide();
782 _button_autocool_reheat->hide();
783 }
784 }
785
render_parameters_changed()786 void EvolvotronMain::render_parameters_changed()
787 {
788 for (std::set<MutatableImageDisplay*>::iterator it=_known_displays.begin();it!=_known_displays.end();it++)
789 (*it)->image_function((*it)->image_function(),true);
790 }
791