Imported Upstream version 0.6.1
Axel Beckert
11 years ago
0 | 0 | [Most recent at top] |
1 | ||
2 | From release 0.6.0: | |
3 | - Version to 0.6.1 | |
4 | - Fix bug in saved functions: quotes missing around version attribute | |
5 | ||
6 | From release 0.5.1: | |
7 | - Version to 0.6.0 | |
8 | - Switch to Qt4. | |
9 | - (Qt4 related) keyboard shortcuts rationalized | |
10 | many removed, ctrl-modifiers dropped | |
11 | - (Qt4 related) image displays now have a frame around them | |
12 | - (Qt4 related) Remove non-standard Qt animated PNG support | |
13 | - evolvotron_match removed | |
14 | - Platform specific code (e.g number of processors identification) | |
15 | isolated in libevolvotron/platform_specific.[h|cpp] | |
16 | and selected by PLATFORM_LINUX or PLATFORM_BSD | |
17 | (Fink Qt's __DARWIN_X11__ also detected and used to select PLATFORM_BSD). | |
18 | - Repository migrated to svn | |
1 | 19 | |
2 | 20 | From release 0.5.0: |
3 | 21 | - Version to 0.5.1 |
97 | 97 | you probably need to install a Qt development tools package |
98 | 98 | of some sort before you can build evolvotron. |
99 | 99 | |
100 | The 0.5.0 code is believed to build against Boost 1.33 or 1.34. | |
100 | The 0.6.0 code builds against Boost 1.35 | |
101 | ||
102 | Non-linux platform issues | |
103 | ------------------------- | |
104 | On the whole, Qt does an excellent job of insulating code from | |
105 | platform specific details. However, there is a little bit of | |
106 | linux-specific code in evolvotron. | |
107 | ||
108 | If you don't have a PLATFORM_... define set, you'll get some warnings | |
109 | about no default implementations of functions in platform_specific.cpp, | |
110 | but should still get a working evolvotron (although missing some functionality | |
111 | with regard to automatically choosing how many threads to run and controlling | |
112 | thread priority). | |
113 | ||
114 | All the platform specific code should live in | |
115 | libevolvtron/platform_specific.cpp | |
116 | and is selected by compile options | |
117 | -DPLATFORM_LINUX or -DPLATFORM_BSD | |
118 | (with more potentially addable for other platforms). | |
119 | ||
120 | Setting the appropriate build options is most easily set by editing | |
121 | an appropriate | |
122 | DEFINES+=PLATFORM_LINUX | |
123 | or | |
124 | DEFINES+=PLATFORM_BSD | |
125 | near the top of the | |
126 | common.pro | |
127 | file. Qt doesn't make a fine enough distinction between unix platforms | |
128 | to decide completely automatically, and the situation is further complicated | |
129 | by e.g Fink's Qt not considering itself to be a Qt 'macx' build. | |
101 | 130 | |
102 | 131 | Long story |
103 | 132 | ---------- |
104 | 133 | [These days the author primarily develops on Debian stable |
105 | 134 | or testing. The comments below re RedHat are based on experience |
106 | with RH8&9; they may or may not be applicable to Fedora.] | |
135 | with the now very old RH 8 & 9; they may or may not be applicable | |
136 | to Fedora.] | |
107 | 137 | |
108 | 138 | QTDIR should point to your Qt installation. Your Qt installation |
109 | 139 | should be a directory somewhere (it might be /usr/share/qt3, it |
166 | 196 | |
167 | 197 | BUILDING ON OTHER PLATFORMS |
168 | 198 | =========================== |
199 | [Very old information now!] | |
169 | 200 | |
170 | 201 | Linc Davis reports: |
171 | 202 | "I built it on a Mac with Qt installed via Fink (if you know what that is.) |
221 | 252 | An unsuccessful experiment: |
222 | 253 | ./evolvotron_match/evolvotron_match |
223 | 254 | |
224 | There are NO extra supporting files | |
225 | (e.g libraries, config files, resource files) | |
255 | There are NO extra supporting files built | |
256 | (e.g shared libraries, config files, "resource" files) | |
226 | 257 | which need to be in special places for the software to work. |
258 | ||
259 | PACKAGING | |
260 | ========= | |
261 | There are a few things which might be useful to packagers: | |
262 | ||
263 | mkdeb | |
264 | - script to build .deb files (using the strangely unpopular | |
265 | "yada", and pbuilder). This is used to build the .debs put | |
266 | up on sourceforge, but the "official" Debian ones (and Ubuntu | |
267 | derivatives) are more conventionally packaged by Gurkan Sengun. | |
268 | ||
269 | rpm/ | |
270 | - directory for contributed RPM related resources. | |
227 | 271 | |
228 | 272 | BUILDING CODE DOCUMENTATION |
229 | 273 | =========================== |
234 | 278 | The code documentation then appears in ./doc/html/ |
235 | 279 | This hasn't been tested in a long while now, although the |
236 | 280 | doxygen commenting style has been kept up. |
237 |
0 | 0 | Proximity to one end or the other of this list does not necessarily |
1 | 1 | imply it will be done sooner or later than other items! |
2 | 2 | |
3 | Consequences of Qt4 port | |
4 | ------------------------ | |
5 | mutableimagedisplay actions need attention - hmmm shorcuts would need to be installed for the grid, then dispatched. | |
6 | Margins in display grid - add command line option to control size ? | |
7 | Why was DialogMutatableImageDisplay created with :QDialog(parent,0,TRUE) ? | |
8 | EvolvotronMain destructor called on close ? | |
9 | statusbar needs right justification ? | |
10 | New-style include files; move to common | |
11 | Lots of Qthingy* stuff needn't be declared in headers; clean up | |
12 | ||
3 | 13 | Conventional Mode |
4 | 14 | ----------------- |
15 | - Use "headache" to manage all copyright notices | |
16 | - Just make "fullscreen mode support" be the default (and remove text in USAGE). | |
17 | - Link on webpage to gallery http://gigrafx.110mb.com/evolvotron/index.html | |
18 | - Mouse manipulations: frame rate should be clamped to allow some time to produce a nice image | |
19 | - At least split out evolvotron_main_history.cpp, even if the class remains nested in .h | |
20 | - Smaller fragments for big enlargements; seeing unused processors. | |
5 | 21 | - More feedback on when enlargements are ready for saving (have split tasks count now... need more ? yes) |
22 | ||
23 | - Enlargement menu: submenus for square, 4:3, 8:5, 16:9. 5:4 SXGA 1024x1024 is a bit of an oddball. | |
24 | And name them, see http://en.wikipedia.org/wiki/Computer_display_standard | |
6 | 25 | |
7 | 26 | - Friezegroups: |
8 | 27 | Cut taken out for 0.5.0 release. |
62 | 62 | evolvotron actions which bring up dialog boxes (e.g save) seem |
63 | 63 | to generally behave fairly sensibly but child windows |
64 | 64 | (e.g enlargements or dialogs) can show some "interesting" behaviour. |
65 | Fullscreen mode can be toggled within the application using ctrl-f. | |
66 | The Esc key will also exit it. | |
65 | Fullscreen mode can be toggled within the application using "F" key. | |
66 | The "Esc" key will also exit it. | |
67 | 67 | |
68 | 68 | -g <cols> <rows> |
69 | 69 | Sets number of image display cells (defaults to 6 by 5) |
104 | 104 | |
105 | 105 | -t <threads> |
106 | 106 | Sets number of compute threads. |
107 | If this is not specified, as many compute threads are created | |
107 | If this is not specified, then as many compute threads are created | |
108 | 108 | as there are processors on the system (unless this cannot be |
109 | discovered, in which case only a single compute thread is created). | |
109 | discovered in which case only a single compute thread is created). | |
110 | Non-linux builds will likely not include code to determine processor count | |
111 | (suitable patches gratefully received). | |
110 | 112 | |
111 | 113 | ANIMATION OPTIONS |
112 | 114 | ----------------- |
205 | 207 | mode is probably what you want in this case as the image will |
206 | 208 | automatically be rendered at the correct resolution). |
207 | 209 | |
208 | - "Save image" to save the image in a file (.ppm, .png or .qt-mng | |
209 | format; qt-mng is Qt's proprietary version of MNG and not very | |
210 | useful). You generally want to save an enlarged image: if you | |
210 | - "Save image" to save the image in a file (.ppm or .png). | |
211 | You generally want to save an enlarged image: if you | |
211 | 212 | save a small image from the grid, the size you see on the screen |
212 | 213 | is the size you get in the file. Save isn't allowed until the |
213 | 214 | full resolution image has been generated; if you try to save too |
234 | 235 | |
235 | 236 | MIDDLE MOUSE BUTTON |
236 | 237 | ------------------- |
237 | [NB This feature will probably only be of practical use to those with multi-GHz machines]. | |
238 | [NB This feature will probably only be of practical use to those with high-end machines]. | |
238 | 239 | |
239 | 240 | You can use the middle mouse button to drag-adjust individual images. |
240 | 241 | This is useful for "final composition" type tweaks, e.g centering an |
274 | 275 | KEYBOARD CONTROL |
275 | 276 | ================ |
276 | 277 | |
278 | There are some keyboard shortcuts. | |
279 | ||
277 | 280 | MAIN WINDOW |
278 | 281 | ----------- |
279 | 282 | |
280 | - Ctrl-f [NB only available with fullscreen build option] toggles | |
283 | - "r"/"t"/"x" perform various starts of reset/restart. | |
284 | ||
285 | - "q" quits the application. | |
286 | ||
287 | - "u" (and also Ctrl-z) does an undo. | |
288 | ||
289 | - "f": [NB only available with fullscreen build option] toggles | |
281 | 290 | full-screen mode (on X11, Qt does this by asking the |
282 | 291 | window manager for a screen-filling undecorated window, and the |
283 | 292 | documentation contains some dire warnings about problems with broken |
286 | 295 | NB The application may completely disappear from the screen for |
287 | 296 | a brief interval while switching mode. |
288 | 297 | |
289 | - Ctrl-m [NB only available with fullscreen build option] | |
290 | toggles status and menu-bar hiding, which can be nice | |
291 | when in full-screen or window-maximised mode. See also "-M" | |
292 | command line option. | |
293 | ||
294 | - Esc [NB only available with fullscreen build option] kills | |
298 | - "m" : [NB only available with fullscreen build option] | |
299 | hides status and menu-bar hiding, which can be nice when | |
300 | in full-screen or window-maximised mode. See also "-M" | |
301 | command line option. Also note that while the menu bar | |
302 | is hidden, most of these keyboard shortcuts won't function | |
303 | as they're tied to the menu system. | |
304 | ||
305 | - Esc : [NB only available with fullscreen build option] kills | |
295 | 306 | full-screen and/or menu-hiding, putting the application |
296 | 307 | into its normal default state. |
297 | ||
298 | - Ctrl-r does a restart (for convenience when the menu bar | |
299 | is hidden, because this is such a common operation). | |
300 | ||
301 | - Ctrl-z does an undo. | |
302 | 308 | |
303 | 309 | ENLARGEMENT WINDOWS |
304 | 310 | ------------------- |
305 | 311 | The image display windows created by selecting "Enlarge" from a |
306 | 312 | context menu also have a couple of keyboard operations: |
307 | 313 | |
308 | - Ctrl-f [NB only available with fullscreen build option] toggles | |
314 | - "f" : [NB only available with fullscreen build option] toggles | |
309 | 315 | full-screen mode. When returning to normal mode, if the main app |
310 | 316 | window was fullscreen then it will also drop back to normal mode. |
311 | 317 | |
312 | - Esc [NB only available with fullscreen build option] | |
318 | - Esc : [NB only available with fullscreen build option] | |
313 | 319 | completely closes a fullscreen-mode enlargement window. |
314 | 320 | |
315 | 321 | GUI ELEMENTS |
423 | 429 | an animated GIF playing at approx. 8 frames per second with: |
424 | 430 | $ convert -delay 12 foo.f??????.ppm foo.gif |
425 | 431 | |
426 | If you save an animation as "QT-MNG" a single file will be | |
427 | generated. NB THIS IS IN A PROPRIETARY QT FORMAT WHICH PREDATES | |
428 | MULTI-FRAME PNG (also known as MNG) AND IS UNLIKELY TO BE | |
429 | READABLE BY ANYTHING OTHER THAN QT PROGRAMS. So it's not | |
430 | actually very useful. Image viewers will generally recognise | |
431 | it as PNG and display the first frame, but that's all. | |
432 | ||
433 | 432 | ADVANCED USAGE |
434 | 433 | ============== |
435 | 434 | Evolvotron's idea of an image is a function which converts |
541 | 540 | as evolvotron in its default state) and writes the new function's XML |
542 | 541 | representation to the standard output. |
543 | 542 | |
544 | $ evolvotron_match [-v] image[.ppm | .png] | |
545 | An experiment in replacing the human operator with a simple scoring function | |
546 | (minimise sum-of-squares of pixel value differences between evolvotron | |
547 | image and image specified on command line). Outputs f??????.png whenever | |
548 | it finds a better match. Terminates after 10000000 iterations and writes | |
549 | match.png. However, all it has ever done so far is to converge with the | |
550 | average colour of the target image. | |
551 | ||
552 | 543 | EXAMPLES |
553 | 544 | -------- |
554 | 545 | |
586 | 577 | - Goetz Waschk |
587 | 578 | - Forrest Walter |
588 | 579 | |
580 | And to the anonymous Linspire reviewer who perhaps came up with the best | |
581 | summary of evolvotron yet: "Fascinating. Utterly pointless, but fascinating." | |
582 | ||
589 | 583 | The friezegroups wouldn't have been possible without |
590 | 584 | http://michaelshepperd.tripod.com/resources/groups.html |
591 | 585 | |
592 | And to www.di.fm, www.somafm.com and Trance4Ever for music to code to. | |
593 | ||
594 | But especially to a SIGGRAPH conference panel many years ago (likely | |
595 | including Karl Sims) who first got me interested in this kind of thing. | |
586 | Thanks to www.di.fm, www.somafm.com and Trance4Ever for music to code to. | |
587 | ||
588 | Thanks especially to a SIGGRAPH conference panel many years ago (likely | |
589 | including Karl Sims, the pioneer in this area) who first got me interested | |
590 | in this stuff. | |
596 | 591 | |
597 | 592 | WHY ? |
598 | 593 | ===== |
4 | 4 | |
5 | 5 | # NB If you edit this, "make distclean" and then rebuild (./BUILD) as there is no dependency checking |
6 | 6 | |
7 | echo "0.5.1" | |
7 | echo "0.6.1" |
2 | 2 | |
3 | 3 | # append debug or release |
4 | 4 | CONFIG+= qt thread stl precompile_header exceptions release #release #debug |
5 | QT += xml | |
6 | ||
7 | ####################################### | |
8 | # Control platform specific code | |
9 | # (the Qt platform scopes don't seem that useful; might be easier to just add DEFINES+=... explicitly | |
10 | ||
11 | unix { | |
12 | DEFINES+=PLATFORM_LINUX # of course PLATFORM_BSD is more appropriate to some unices | |
13 | } | |
14 | ||
15 | macx { | |
16 | # NB This doesn't actually seem to be selected on Fink builds | |
17 | # (presumably it applies to Quartz builds instead) | |
18 | # Fink does seem to have a useful __DARWIN_X11__ define though, | |
19 | # which is used to set PLATFORM_BSD in libevolvotron/platform_specific.cpp | |
20 | DEFINES+=PLATFORM_BSD | |
21 | } | |
22 | ||
23 | win32 { | |
24 | # You might want to add some appropriate code to libevolvotron/platform_specific.cpp | |
25 | # and set a #define here to select it | |
26 | } | |
5 | 27 | |
6 | 28 | ####################################### |
7 | 29 | # Version numbering. VERSION_NUMBER should have been set on the qmake command line (see .configure script) |
26 | 48 | # NB We don't use the corresponding -DQT_NO_CAST_ASCII because it breaks QString("...") which is used all over the place |
27 | 49 | # This probably wouldn't be usable until all the strings were moved out of the app - see Qt I18N docs. |
28 | 50 | # Also add gcc threading option (not entirely clear whether this is needed but it doesn't seem to hurt) |
29 | ||
30 | QMAKE_CXXFLAGS_RELEASE += -DQT_NO_ASCII_CAST -pthread | |
31 | QMAKE_CXXFLAGS_DEBUG += -DQT_NO_ASCII_CAST -pthread | |
51 | # -DBOOST_SP_USE_PTHREADS is a workround for debian bug 485434 (maybe only needed on sparc?) | |
52 | QMAKE_CXXFLAGS_RELEASE += -DQT_NO_ASCII_CAST -pthread -DBOOST_SP_USE_PTHREADS | |
53 | QMAKE_CXXFLAGS_DEBUG += -DQT_NO_ASCII_CAST -pthread -DBOOST_SP_USE_PTHREADS | |
32 | 54 | |
33 | 55 | ###################################### |
34 | 56 | # Hide those crufty moc_ files away |
11 | 11 | # TODO?: Should perhaps test "which qmake" here. |
12 | 12 | # If not found, add $(QTDIR)/bin to path. But the ./BUILD script does that. |
13 | 13 | echo "Your qmake version is:" |
14 | qmake --version | |
14 | qmake-qt4 --version | |
15 | 15 | |
16 | 16 | echo |
17 | 17 | echo "Your gcc version is (unless qmake is set up to use a different one):" |
28 | 28 | VERSION_NUMBER=`./VERSION` |
29 | 29 | |
30 | 30 | echo |
31 | echo "Running qmake with CONFIG_OPTS=$CONFIG_OPTS VERSION_NUMBER=$VERSION_NUMBER..." | |
31 | echo "Running qmake-qt4 with CONFIG_OPTS=$CONFIG_OPTS VERSION_NUMBER=$VERSION_NUMBER..." | |
32 | 32 | |
33 | qmake "CONFIG_OPTS=$CONFIG_OPTS" "VERSION_NUMBER=$VERSION_NUMBER" main.pro | |
33 | qmake-qt4 "CONFIG_OPTS=$CONFIG_OPTS" "VERSION_NUMBER=$VERSION_NUMBER" main.pro | |
34 | 34 | |
35 | 35 | echo "...configuration completed - ready to do 'make' now" |
34 | 34 | #include "evolvotron_precompiled.h" |
35 | 35 | |
36 | 36 | #include "args.h" |
37 | #include "platform_specific.h" | |
38 | ||
37 | 39 | #include "evolvotron_main.h" |
38 | 40 | |
39 | 41 | //! Application code |
62 | 64 | exit(1); |
63 | 65 | } |
64 | 66 | |
65 | uint threads=1; | |
67 | uint threads=get_number_of_processors(); | |
66 | 68 | |
67 | 69 | if (args.option("-t",1)) |
68 | 70 | { |
69 | 71 | args.after() >> threads; |
70 | 72 | if (threads<1) |
71 | 73 | { |
72 | std::cerr << "Must specify at least one compute thread (option: -t <threads>)\n"; | |
74 | std::cerr << "Must specify at least one thread for option -t <threads>)\n"; | |
73 | 75 | exit(1); |
74 | 76 | } |
75 | 77 | } |
76 | else | |
77 | { | |
78 | /*! \todo: People porting to non-Linux (BSD, MacOS, Fink etc) please send | |
79 | a suitable #ifdef-able patch if you need something different here. | |
80 | */ | |
81 | cpu_set_t cpus; | |
82 | if (sched_getaffinity(0,sizeof(cpu_set_t),&cpus)!=0) | |
83 | { | |
84 | std::cerr << "Could not determine number of CPUs; defaulting to " << threads << " compute thread\n"; | |
85 | } | |
86 | else | |
87 | { | |
88 | threads=0; | |
89 | for (int i=0;i<CPU_SETSIZE;i++) | |
90 | { | |
91 | if (CPU_ISSET(i,&cpus)) threads++; | |
92 | } | |
93 | } | |
94 | } | |
78 | ||
95 | 79 | std::clog << "Using " << threads << " threads\n"; |
96 | 80 | |
97 | 81 | int niceness_grid=4; |
144 | 128 | |
145 | 129 | std::clog |
146 | 130 | << "Evolvotron version " |
147 | << EVOLVOTRON_BUILD | |
131 | << stringify(EVOLVOTRON_BUILD) | |
148 | 132 | << " starting with " |
149 | 133 | << cols |
150 | 134 | << " by " |
194 | 178 | main_widget->favourite_function_unwrapped(favourite_function_unwrapped); |
195 | 179 | } |
196 | 180 | |
197 | app.setMainWidget(main_widget); | |
198 | 181 | main_widget->show(); |
199 | ||
182 | ||
200 | 183 | // NB Do this here rather than in constructor so that compute threads aren't being fired off during general GUI set-up |
201 | 184 | |
202 | 185 | std::clog << "Resetting main widget...\n"; |
203 | 186 | main_widget->reset_cold(); |
204 | ||
187 | ||
205 | 188 | // NB No need to worry about deleting EvolvotronMain... QApplication seems to do it for us. |
206 | 189 | std::clog << "Commencing main loop...\n"; |
207 | 190 | return app.exec(); |
24 | 24 | |
25 | 25 | #include "libevolvotron_precompiled.h" |
26 | 26 | |
27 | // Used for determining number of processors. | |
28 | #include <sched.h> | |
29 | ||
30 | 27 | #endif |
0 | // Source file for evolvotron | |
1 | // Copyright (C) 2004 Tim Day | |
2 | /*! \page License License | |
3 | ||
4 | This program is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU General Public License | |
6 | as published by the Free Software Foundation; either version 2 | |
7 | of the License, or (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
17 | */ | |
18 | ||
19 | /*! \file | |
20 | \brief Mutate functions searching for a match to a given image. | |
21 | */ | |
22 | ||
23 | #include "evolvotron_match_precompiled.h" | |
24 | ||
25 | #include "args.h" | |
26 | #include "mutatable_image.h" | |
27 | #include "mutation_parameters.h" | |
28 | ||
29 | //! A QImage which deletes it's data on destruction | |
30 | class QImageWithData | |
31 | { | |
32 | public: | |
33 | QImageWithData(uchar* data,int w,int h,int depth,QRgb* colortable,int numColors,QImage::Endian bitOrder) | |
34 | :_image(new QImage(data,w,h,depth,colortable,numColors,bitOrder)) | |
35 | ,_data(data) | |
36 | {} | |
37 | ||
38 | virtual ~QImageWithData() | |
39 | {} | |
40 | ||
41 | QImage*const image() | |
42 | { | |
43 | return _image.get(); | |
44 | } | |
45 | const QImage*const image() const | |
46 | { | |
47 | return _image.get(); | |
48 | } | |
49 | ||
50 | protected: | |
51 | const std::auto_ptr<QImage> _image; | |
52 | const std::auto_ptr<uchar> _data; | |
53 | }; | |
54 | ||
55 | //! Render a new QImage of the given mutatable image | |
56 | QImageWithData*const render_image(const MutatableImage*const imagefn,int width,int height) | |
57 | { | |
58 | uint*const image_data=new uint[width*height]; | |
59 | uint* pixel=image_data; | |
60 | ||
61 | for (int row=0;row<height;row++) | |
62 | for (int col=0;col<width;col++,pixel++) | |
63 | { | |
64 | // xy co-ords vary over -1.0 to 1.0. In the one frame case z will be 0 | |
65 | const XYZ p( | |
66 | -1.0+2.0*(col+0.5)/width, | |
67 | 1.0-2.0*(row+0.5)/height, | |
68 | 0.0 | |
69 | ); | |
70 | ||
71 | const XYZ c(imagefn->get_rgb(p)); | |
72 | ||
73 | const uint col0=lrint(clamped(c.x(),0.0,255.0)); | |
74 | const uint col1=lrint(clamped(c.y(),0.0,255.0)); | |
75 | const uint col2=lrint(clamped(c.z(),0.0,255.0)); | |
76 | ||
77 | *pixel=((col0<<16)|(col1<<8)|(col2)); | |
78 | } | |
79 | ||
80 | return new QImageWithData | |
81 | ( | |
82 | reinterpret_cast<uchar*>(image_data), | |
83 | width, | |
84 | height, | |
85 | 32, | |
86 | 0, | |
87 | 0, | |
88 | QImage::LittleEndian | |
89 | ); | |
90 | } | |
91 | ||
92 | const double compare_images(const QImage* src0,const QImage* src1) | |
93 | { | |
94 | double t=0.0; | |
95 | ||
96 | assert(src0->width()==src1->width() && src0->height()==src1->height()); | |
97 | ||
98 | for (int y=0;y<src0->height();y++) | |
99 | { | |
100 | for (int x=0;x<src0->width();x++) | |
101 | { | |
102 | //! \todo Optimise pixel accesses. | |
103 | const QRgb col0(src0->pixel(x,y)); | |
104 | const QRgb col1(src1->pixel(x,y)); | |
105 | ||
106 | const real r0=qRed(col0); | |
107 | const real r1=qRed(col1); | |
108 | const real g0=qGreen(col0); | |
109 | const real g1=qGreen(col1); | |
110 | const real b0=qBlue(col0); | |
111 | const real b1=qBlue(col1); | |
112 | t+=sqr(r0-r1)+sqr(g0-g1)+sqr(b0-b1); | |
113 | } | |
114 | } | |
115 | ||
116 | return t/(255.0*src0->width()*src0->height()); | |
117 | } | |
118 | ||
119 | //! Application code | |
120 | int main(int argc,char* argv[]) | |
121 | { | |
122 | { | |
123 | Args args(argc,argv); | |
124 | ||
125 | if (args.option("-v")) | |
126 | std::clog.rdbuf(std::cerr.rdbuf()); | |
127 | else | |
128 | std::clog.rdbuf(sink_ostream.rdbuf()); | |
129 | ||
130 | // Normally would use time(0) to seed random number generator | |
131 | // but can imagine several of these starting up virtually simultaneously | |
132 | // so need something with higher resolution. | |
133 | // Adding the process id too to keep things unique. | |
134 | ||
135 | QTime t(QTime::currentTime()); | |
136 | uint seed=getpid()+t.msec()+1000*t.second()+60000*t.minute()+3600000*t.hour(); | |
137 | std::clog << "Random seed is " << seed << "\n"; | |
138 | ||
139 | MutationParameters mutation_parameters(seed,false,false); | |
140 | ||
141 | if (argc<2) | |
142 | { | |
143 | std::cerr << "Must supply a filename\n"; | |
144 | exit(1); | |
145 | } | |
146 | ||
147 | QImage target_image(args.last(1).c_str()); | |
148 | if (target_image.isNull()) | |
149 | { | |
150 | std::cerr << "Couldn't load target image\n"; | |
151 | exit(1); | |
152 | } | |
153 | ||
154 | const uint fresh=10; | |
155 | const uint reset=100; | |
156 | const real cooling=0.9; | |
157 | const uint iterations=10000000; | |
158 | ||
159 | std::clog << "Cumulative cooling effect is " << pow(cooling,reset) << " over cycle\n"; | |
160 | ||
161 | double best_score=0.0; | |
162 | boost::shared_ptr<const QImageWithData> best_image; | |
163 | boost::shared_ptr<const MutatableImage> best_imagefn; | |
164 | ||
165 | for (uint i=0,output_frame=0;i<iterations;i++) | |
166 | { | |
167 | if (i%reset==0) | |
168 | { | |
169 | mutation_parameters.reset(); | |
170 | } | |
171 | else | |
172 | { | |
173 | mutation_parameters.general_cool(cooling); | |
174 | } | |
175 | ||
176 | boost::shared_ptr<const MutatableImage> new_imagefn; | |
177 | ||
178 | if (best_imagefn==0 || i%fresh==0) | |
179 | { | |
180 | do | |
181 | { | |
182 | new_imagefn=boost::shared_ptr<const MutatableImage>(new MutatableImage(mutation_parameters,true,true,false)); | |
183 | } | |
184 | while (new_imagefn->is_constant()); | |
185 | } | |
186 | else | |
187 | { | |
188 | new_imagefn=boost::shared_ptr<const MutatableImage>(best_imagefn->mutated(mutation_parameters)); | |
189 | } | |
190 | ||
191 | ||
192 | boost::shared_ptr<const QImageWithData> new_image | |
193 | =boost::shared_ptr<const QImageWithData>(render_image(new_imagefn.get(),target_image.width(),target_image.height())); | |
194 | ||
195 | const double score=compare_images(new_image->image(),&target_image); | |
196 | ||
197 | if (best_image.get()==0 || score<best_score) | |
198 | { | |
199 | best_score=score; | |
200 | best_image=new_image; | |
201 | best_imagefn=new_imagefn; | |
202 | std::stringstream filename; | |
203 | filename << "f" << std::setw(6) << std::setfill('0') << output_frame++ << ".png"; | |
204 | best_image->image()->save(filename.str().c_str(),"PNG"); | |
205 | std::clog << "[" << best_score << "]"; | |
206 | } | |
207 | else | |
208 | { | |
209 | std::clog << "."; | |
210 | } | |
211 | } | |
212 | ||
213 | best_image->image()->save("match.png","PNG"); | |
214 | } | |
215 | ||
216 | #ifndef NDEBUG | |
217 | assert(InstanceCounted::is_clear()); | |
218 | #endif | |
219 | ||
220 | exit(0); | |
221 | } |
0 | TEMPLATE = app | |
1 | ||
2 | include (../common.pro) | |
3 | ||
4 | PRECOMPILED_HEADER = evolvotron_match_precompiled.h | |
5 | ||
6 | SOURCES += evolvotron_match.cpp | |
7 | ||
8 | DEPENDPATH += ../libevolvotron ../libfunction | |
9 | INCLUDEPATH += ../libevolvotron ../libfunction | |
10 | ||
11 | TARGETDEPS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a | |
12 | LIBS += ../libevolvotron/libevolvotron.a ../libfunction/libfunction.a |
0 | // Source file for evolvotron | |
1 | // Copyright (C) 2007 Tim Day | |
2 | /* | |
3 | This program is free software; you can redistribute it and/or | |
4 | modify it under the terms of the GNU General Public License | |
5 | as published by the Free Software Foundation; either version 2 | |
6 | of the License, or (at your option) any later version. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU General Public License for more details. | |
12 | ||
13 | You should have received a copy of the GNU General Public License | |
14 | along with this program; if not, write to the Free Software | |
15 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | /*! \file | |
19 | \brief Precompiled header for evolvotron_match | |
20 | */ | |
21 | ||
22 | #ifndef _evolvotron_match_precompiled_h_ | |
23 | #define _evolvotron_match_precompiled_h_ | |
24 | ||
25 | #include "libevolvotron_precompiled.h" | |
26 | ||
27 | #endif |
108 | 108 | QString save_filename(QString::fromLocal8Bit(args.last(1).c_str())); |
109 | 109 | |
110 | 110 | const char* save_format="PPM"; |
111 | if (save_filename.upper().endsWith(".PPM")) | |
111 | if (save_filename.toUpper().endsWith(".PPM")) | |
112 | 112 | { |
113 | 113 | save_format="PPM"; |
114 | 114 | } |
115 | else if (save_filename.upper().endsWith(".PNG")) | |
115 | else if (save_filename.toUpper().endsWith(".PNG")) | |
116 | 116 | { |
117 | 117 | save_format="PNG"; |
118 | 118 | } |
128 | 128 | { |
129 | 129 | QString frame_component; |
130 | 130 | frame_component.sprintf(".f%06d",frame); |
131 | int insert_point=save_filename.findRev(QString(".")); | |
131 | int insert_point=save_filename.lastIndexOf(QString(".")); | |
132 | 132 | if (insert_point==-1) |
133 | 133 | { |
134 | 134 | save_filename.append(frame_component); |
140 | 140 | } |
141 | 141 | |
142 | 142 | QImage image( |
143 | (uchar*)&(image_data[0]), | |
143 | reinterpret_cast<uchar*>(&(image_data[0])), | |
144 | 144 | width, |
145 | 145 | height, |
146 | 32, | |
147 | 0, | |
148 | 0, | |
149 | QImage::LittleEndian | |
146 | QImage::Format_RGB32 | |
150 | 147 | ); |
151 | 148 | |
152 | 149 | if (!image.save(save_filename,save_format)) |
153 | 150 | { |
154 | 151 | std::cerr |
155 | 152 | << "evolvotron_render: Error: Couldn't save file " |
156 | << save_filename.local8Bit() | |
153 | << save_filename.toLocal8Bit().data() | |
157 | 154 | << "\n"; |
158 | 155 | exit(1); |
159 | 156 | } |
160 | 157 | |
161 | 158 | std::clog |
162 | 159 | << "Wrote file " |
163 | << save_filename.local8Bit() | |
160 | << save_filename.toLocal8Bit().data() | |
164 | 161 | << "\n"; |
165 | 162 | } |
166 | 163 | } |
0 | #include <stdexcept> | |
1 | ||
2 | #include <QApplication> | |
3 | #include <QGLWidget> | |
4 | #include <QSvgRenderer> | |
5 | ||
6 | #include <QtOpenGL/qgl.h> | |
7 | ||
8 | #include <QtSvg> | |
9 | ||
10 | // Following file:///usr/share/doc/qt4-doc-html/html/opengl-overpainting.html | |
11 | // for combining OpenGL with 2D | |
12 | ||
13 | // Looks nicer run with e.g __GL_FSAA_MODE=13 ./svg | |
14 | ||
15 | // TODO: Benchmark. Try and capture SVG rendering in a display list. | |
16 | ||
17 | class View : public QGLWidget | |
18 | { | |
19 | public: | |
20 | View() | |
21 | :QGLWidget() | |
22 | ,_renderer(this) | |
23 | { | |
24 | setAutoFillBackground(false); | |
25 | ||
26 | if (!_renderer.load(QString("drawing.svg"))) | |
27 | throw std::runtime_error(__PRETTY_FUNCTION__+std::string(": loading SVG file failed\n")); | |
28 | } | |
29 | ||
30 | void initializeGL() | |
31 | {} | |
32 | ||
33 | //Don't use paintGL when combining 2D/3D | |
34 | //void paintGL() | |
35 | //{} | |
36 | ||
37 | void paintEvent(QPaintEvent*) | |
38 | { | |
39 | glViewport(0,0,static_cast<GLint>(width()),static_cast<GLint>(height())); | |
40 | ||
41 | glClearColor(1.0f,1.0f,1.0f,1.0f); | |
42 | glClear(GL_COLOR_BUFFER_BIT); | |
43 | ||
44 | //glEnable(GL_MULTISAMPLE); | |
45 | ||
46 | QPainter painter(this); | |
47 | painter.setRenderHint(QPainter::Antialiasing); | |
48 | _renderer.render(&painter); | |
49 | painter.end(); | |
50 | } | |
51 | protected: | |
52 | void resizeGL(int width,int height) | |
53 | { | |
54 | glViewport(0,0,static_cast<GLint>(width),static_cast<GLint>(height)); | |
55 | } | |
56 | private: | |
57 | QSvgRenderer _renderer; | |
58 | }; | |
59 | ||
60 | int main(int argc,char** argv) | |
61 | { | |
62 | QApplication app(argc,argv); | |
63 | ||
64 | QWidget*const w=new View(); | |
65 | ||
66 | w->show(); | |
67 | ||
68 | return app.exec(); | |
69 | } | |
70 |
0 | TEMPLATE = app | |
1 | ||
2 | CONFIG+= qt opengl stl exceptions release # release debug | |
3 | QT += opengl svg | |
4 | ||
5 | SOURCES += svg.cpp | |
6 | ||
7 | ####################################### | |
8 | # Disable assertions in release version | |
9 | ||
10 | QMAKE_CXXFLAGS_RELEASE += -DNDEBUG | |
11 | QMAKE_CFLAGS_RELEASE += -DNDEBUG | |
12 | ||
13 | ###################################### | |
14 | # Other stuff: | |
15 | # Disable implicit cast from QString to char* | |
16 | ||
17 | QMAKE_CXXFLAGS_RELEASE += -DQT_NO_ASCII_CAST | |
18 | QMAKE_CXXFLAGS_DEBUG += -DQT_NO_ASCII_CAST | |
19 | ||
20 | ###################################### | |
21 | # Hide those crufty moc_ files away | |
22 | ||
23 | MOC_DIR = moc | |
24 | OBJECTS_DIR = obj |
28 | 28 | DialogAbout::DialogAbout(QWidget* parent,int n_threads,bool separate_farm_for_enlargements) |
29 | 29 | :QDialog(parent) |
30 | 30 | { |
31 | setCaption("About evolvotron"); | |
32 | setMinimumSize(400,300); | |
31 | assert(parent!=0); | |
33 | 32 | |
34 | _vbox=new QVBox(this); | |
33 | setWindowTitle("About evolvotron"); | |
34 | setMinimumSize(480,360); | |
35 | setSizeGripEnabled(true); | |
35 | 36 | |
36 | QTabWidget* tabs=new QTabWidget(_vbox); | |
37 | QVBox* vbox_info=new QVBox(tabs); | |
38 | tabs->addTab(vbox_info,"Info"); | |
39 | QVBox* vbox_license=new QVBox(tabs); | |
40 | tabs->addTab(vbox_license,"License"); | |
37 | setLayout(new QVBoxLayout); | |
38 | ||
39 | QTabWidget*const tabs=new QTabWidget; | |
40 | layout()->addWidget(tabs); | |
41 | ||
42 | QWidget*const tab_info=new QWidget; | |
43 | tab_info->setLayout(new QVBoxLayout); | |
44 | tabs->addTab(tab_info,"Info"); | |
45 | ||
46 | QWidget*const tab_license=new QWidget; | |
47 | tab_license->setLayout(new QVBoxLayout); | |
48 | tabs->addTab(tab_license,"License"); | |
41 | 49 | |
42 | 50 | std::ostringstream about_string; |
43 | 51 | about_string |
44 | 52 | << "Evolvotron " |
45 | << EVOLVOTRON_BUILD | |
53 | << stringify(EVOLVOTRON_BUILD) | |
46 | 54 | << "\n\n" |
47 | 55 | << "Using " |
48 | 56 | << (separate_farm_for_enlargements ? "2 pools" : "1 pool") |
55 | 63 | << "Home page: http://evolvotron.sourceforge.net\n" |
56 | 64 | << "Project page: http://sourceforge.net/projects/evolvotron\n"; |
57 | 65 | |
58 | _label=new QLabel(about_string.str().c_str(),vbox_info); | |
59 | _label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter|_label->alignment()); | |
66 | QLabel*const label=new QLabel(about_string.str().c_str()); | |
67 | tab_info->layout()->addWidget(label); | |
68 | label->setAlignment(Qt::AlignHCenter|Qt::AlignVCenter|label->alignment()); | |
60 | 69 | |
61 | _license=new QTextEdit(vbox_license); | |
62 | _license->setReadOnly(true); | |
63 | _license->setTextFormat(PlainText); | |
64 | _license->setText((std::string("License:\n")+std::string(license_string)).c_str()); | |
70 | QTextEdit*const license=new QTextEdit; | |
71 | tab_license->layout()->addWidget(license); | |
72 | license->setReadOnly(true); | |
73 | license->setPlainText((std::string("License:\n")+std::string(license_string)).c_str()); | |
65 | 74 | |
66 | _ok=new QPushButton("OK",_vbox); | |
67 | _ok->setDefault(true); | |
75 | QPushButton* ok=new QPushButton("OK"); | |
76 | layout()->addWidget(ok); | |
77 | ok->setDefault(true); | |
68 | 78 | |
69 | connect( | |
70 | _ok,SIGNAL(clicked()), | |
71 | this,SLOT(hide()) | |
72 | ); | |
79 | connect | |
80 | ( | |
81 | ok,SIGNAL(clicked()), | |
82 | this,SLOT(hide()) | |
83 | ); | |
73 | 84 | } |
74 | 85 | |
75 | void DialogAbout::resizeEvent(QResizeEvent* e) | |
76 | { | |
77 | Superclass::resizeEvent(e); | |
78 | _vbox->resize(size()); | |
79 | } | |
86 | DialogAbout::~DialogAbout() | |
87 | {} |
30 | 30 | private: |
31 | 31 | Q_OBJECT |
32 | 32 | |
33 | typedef QDialog Superclass; | |
33 | public: | |
34 | 34 | |
35 | public: | |
36 | 35 | //! Constructor. |
37 | 36 | DialogAbout(QWidget* parent,int n_threads,bool separate_farm_for_enlargements); |
38 | 37 | |
39 | 38 | //! Destructor. |
40 | virtual ~DialogAbout() | |
41 | {} | |
42 | ||
43 | protected: | |
44 | //! Vertical layout. | |
45 | QVBox* _vbox; | |
46 | ||
47 | //! Label for name/release/author etc | |
48 | QLabel* _label; | |
49 | ||
50 | //! Scrolling text area for GPL. | |
51 | QTextEdit* _license; | |
52 | ||
53 | //! Button to close dialog. | |
54 | QPushButton* _ok; | |
55 | ||
56 | //! Need to pass resizes on to vbox or things just get chopped. | |
57 | virtual void resizeEvent(QResizeEvent*); | |
39 | ~DialogAbout(); | |
58 | 40 | }; |
59 | 41 | |
60 | ||
61 | ||
62 | 42 | #endif |
31 | 31 | ,_parent(parent) |
32 | 32 | ,_favourite_function_unwrapped(false) |
33 | 33 | { |
34 | setCaption("Favourite"); | |
34 | setWindowTitle("Favourite"); | |
35 | setSizeGripEnabled(true); | |
36 | ||
37 | setLayout(new QVBoxLayout); | |
35 | 38 | |
36 | _dialog_content=new QVBox(this); | |
37 | ||
38 | QVGroupBox* group0=new QVGroupBox("Function",_dialog_content); | |
39 | QGroupBox*const group0=new QGroupBox("Function"); | |
40 | group0->setLayout(new QVBoxLayout); | |
41 | layout()->addWidget(group0); | |
39 | 42 | |
40 | new QLabel("Root node for new image functions:",group0,0,Qt::WordBreak); | |
41 | _favourite=new QComboBox(false,group0); | |
43 | group0->layout()->addWidget(new QLabel("Root node for new image functions:")); | |
44 | _favourite=new QComboBox; | |
45 | group0->layout()->addWidget(_favourite); | |
42 | 46 | _favourite_fn_to_index[""]=_favourite->count(); |
43 | 47 | _index_to_favourite_fn[_favourite->count()]=""; |
44 | _favourite->insertItem("- No preference -"); | |
48 | _favourite->addItem("- No preference -"); | |
45 | 49 | |
46 | 50 | for (FunctionRegistry::Registrations::const_iterator it=_parent->mutation_parameters().function_registry().registrations().begin(); |
47 | 51 | it!=_parent->mutation_parameters().function_registry().registrations().end(); |
56 | 60 | #endif |
57 | 61 | _favourite_fn_to_index[fn.name()]=_favourite->count(); |
58 | 62 | _index_to_favourite_fn[_favourite->count()]=fn.name(); |
59 | _favourite->insertItem(fn.name()); | |
63 | _favourite->addItem(fn.name().c_str()); | |
60 | 64 | } |
61 | 65 | |
62 | QVGroupBox* group1=new QVGroupBox("Wrapping",_dialog_content); | |
66 | QGroupBox*const group1=new QGroupBox("Wrapping"); | |
67 | group1->setLayout(new QVBoxLayout); | |
68 | layout()->addWidget(group1); | |
63 | 69 | |
64 | _unwrapped=new QCheckBox("Disable additional space/colour transforms\n",group1); | |
70 | _unwrapped=new QCheckBox("Disable additional space/colour transforms"); | |
71 | group1->layout()->addWidget(_unwrapped); | |
65 | 72 | |
66 | 73 | //! \todo: Add OK & reset/restart versions ? |
67 | QPushButton* ok=new QPushButton("OK",_dialog_content); | |
74 | QPushButton*const ok=new QPushButton("OK"); | |
75 | layout()->addWidget(ok); | |
68 | 76 | ok->setDefault(true); |
69 | 77 | |
70 | 78 | update_gui_from_state(); |
97 | 105 | update_gui_from_state(); |
98 | 106 | } |
99 | 107 | |
100 | ||
101 | 108 | void DialogFavourite::update_gui_from_state() |
102 | 109 | { |
103 | 110 | const std::map<std::string,unsigned int>::const_iterator it=_favourite_fn_to_index.find(_favourite_function); |
104 | 111 | if (it!=_favourite_fn_to_index.end()) |
105 | _favourite->setCurrentItem((*it).second); | |
112 | _favourite->setCurrentIndex((*it).second); | |
106 | 113 | else |
107 | _favourite->setCurrentItem(0); | |
114 | _favourite->setCurrentIndex(0); | |
108 | 115 | |
109 | 116 | _unwrapped->setChecked(_favourite_function_unwrapped); |
110 | 117 | |
111 | 118 | _unwrapped->setEnabled(!_favourite_function.empty()); |
112 | 119 | } |
113 | 120 | |
114 | void DialogFavourite::resizeEvent(QResizeEvent* e) | |
115 | { | |
116 | Superclass::resizeEvent(e); | |
117 | _dialog_content->resize(size()); | |
118 | } | |
119 | ||
120 | const bool DialogFavourite::favourite_function(const std::string& f) | |
121 | bool DialogFavourite::favourite_function(const std::string& f) | |
121 | 122 | { |
122 | 123 | if (_parent->mutation_parameters().function_registry().lookup(f)) |
123 | 124 | { |
30 | 30 | private: |
31 | 31 | Q_OBJECT |
32 | 32 | |
33 | typedef QDialog Superclass; | |
34 | ||
35 | 33 | protected: |
36 | 34 | //! Owner. |
37 | 35 | EvolvotronMain* _parent; |
42 | 40 | //! Flag specifying whether favourite function should be exposed |
43 | 41 | bool _favourite_function_unwrapped; |
44 | 42 | |
45 | //! Top level holder of all the dialog content. | |
46 | QVBox* _dialog_content; | |
47 | ||
48 | //! Select favourite function, if any. | |
49 | QComboBox* _favourite; | |
50 | ||
51 | 43 | //! Map function names to combo box entries. |
52 | 44 | std::map<std::string,unsigned int> _favourite_fn_to_index; |
53 | 45 | |
54 | 46 | //! Look up function names from combo box. |
55 | 47 | std::map<unsigned int,std::string> _index_to_favourite_fn; |
48 | ||
49 | //! Select favourite function, if any. | |
50 | QComboBox* _favourite; | |
56 | 51 | |
57 | 52 | //! Controls unwrapped state. |
58 | 53 | QCheckBox* _unwrapped; |
73 | 68 | DialogFavourite(EvolvotronMain* parent); |
74 | 69 | |
75 | 70 | //! Destructor. |
76 | virtual ~DialogFavourite(); | |
71 | ~DialogFavourite(); | |
77 | 72 | |
78 | 73 | //! Accessor |
79 | 74 | const std::string& favourite_function() const |
82 | 77 | } |
83 | 78 | |
84 | 79 | //! Accessor. Returns true if function name recognised. |
85 | const bool favourite_function(const std::string& f); | |
80 | bool favourite_function(const std::string& f); | |
86 | 81 | |
87 | 82 | //! Accessor. |
88 | const bool favourite_function_unwrapped() const | |
83 | bool favourite_function_unwrapped() const | |
89 | 84 | { |
90 | 85 | return _favourite_function_unwrapped; |
91 | 86 | } |
92 | 87 | |
93 | 88 | //! Accessor. |
94 | 89 | void favourite_function_unwrapped(bool v); |
95 | ||
96 | //! Handle resizes. | |
97 | virtual void resizeEvent(QResizeEvent* e); | |
98 | ||
99 | 90 | }; |
100 | 91 | |
101 | 92 | #endif |
0 | 0 | // Source file for evolvotron |
1 | // Copyright (C) 2002,2003,2004 Tim Day | |
1 | // Copyright (C) 2009 Tim Day | |
2 | 2 | /* |
3 | 3 | This program is free software; you can redistribute it and/or |
4 | 4 | modify it under the terms of the GNU General Public License |
23 | 23 | |
24 | 24 | #include "dialog_functions.h" |
25 | 25 | |
26 | #include <qtooltip.h> | |
27 | #include <qtabwidget.h> | |
28 | ||
29 | 26 | #include "evolvotron_main.h" |
30 | 27 | #include "function_registry.h" |
31 | #include "vbox_scrollview.h" | |
32 | ||
33 | /*! About dialog displays author info, web addresses and license info. | |
28 | ||
29 | /*! Dialog controls function weightings and related parameters. | |
34 | 30 | */ |
35 | 31 | DialogFunctions::DialogFunctions(EvolvotronMain* parent,MutationParametersQObject* mp) |
36 | 32 | :QDialog(parent) |
39 | 35 | { |
40 | 36 | assert(_parent!=0); |
41 | 37 | |
42 | setCaption("Functions"); | |
43 | ||
44 | _dialog_content=new QVBox(this); | |
45 | ||
46 | QTabWidget* tabs=new QTabWidget(_dialog_content); | |
47 | _ok=new QPushButton("OK",_dialog_content); | |
48 | _ok->setDefault(true); | |
38 | setWindowTitle("Functions"); | |
39 | setMinimumSize(480,360); // Have to scroll through tabs if don't set this | |
40 | setSizeGripEnabled(true); | |
41 | ||
42 | setLayout(new QVBoxLayout); | |
43 | ||
44 | QTabWidget*const tabs=new QTabWidget; | |
45 | layout()->addWidget(tabs); | |
46 | ||
47 | QPushButton*const ok=new QPushButton("OK"); | |
48 | layout()->addWidget(ok); | |
49 | ok->setDefault(true); | |
49 | 50 | |
50 | 51 | for (int c=-1;c<FnClassifications;c++) |
51 | 52 | { |
52 | QVBox*const tab_content=new QVBox(_dialog_content); | |
53 | QWidget*const tab_content=new QWidget; | |
54 | QVBoxLayout*const tab_content_layout=new QVBoxLayout; | |
55 | tab_content->setLayout(tab_content_layout); | |
53 | 56 | tabs->addTab(tab_content,(c==-1 ? "All" : function_classification_name[c])); |
54 | 57 | |
55 | QHBox*const buttons=new QHBox(tab_content); | |
56 | QPushButton*const button_less=new QPushButton("Less",buttons); | |
57 | QPushButton*const button_rand=new QPushButton("Randomize",buttons); | |
58 | QPushButton*const button_more=new QPushButton("More",buttons); | |
58 | QWidget*const buttons=new QWidget; | |
59 | buttons->setLayout(new QHBoxLayout); | |
60 | tab_content->layout()->addWidget(buttons); | |
61 | QPushButton*const button_less=new QPushButton("Less"); | |
62 | QPushButton*const button_rand=new QPushButton("Randomize"); | |
63 | QPushButton*const button_more=new QPushButton("More"); | |
64 | buttons->layout()->addWidget(button_less); | |
65 | buttons->layout()->addWidget(button_rand); | |
66 | buttons->layout()->addWidget(button_more); | |
59 | 67 | |
60 | 68 | SignalExpanderClickedUint*const bx_rand=new SignalExpanderClickedUint(this,(c==-1 ? 0xffffffff : (1<<c))); |
61 | 69 | |
62 | 70 | connect(button_rand,SIGNAL(clicked()),bx_rand,SLOT(clicked())); |
63 | 71 | connect(bx_rand,SIGNAL(clicked(uint)),this,SLOT(clicked_button_rand(uint))); |
64 | 72 | |
65 | VBoxScrollView* scrollview=new VBoxScrollView(tab_content); | |
66 | tab_content->setStretchFactor(scrollview,1); | |
73 | QScrollArea*const scrollarea=new QScrollArea; | |
74 | scrollarea->setWidgetResizable(true); | |
75 | tab_content->layout()->addWidget(scrollarea); | |
76 | tab_content_layout->setStretchFactor(scrollarea,1); | |
77 | ||
78 | QWidget*const scrollcontent=new QWidget; | |
79 | scrollcontent->setLayout(new QVBoxLayout); | |
80 | scrollarea->setWidget(scrollcontent); | |
67 | 81 | |
68 | 82 | for (FunctionRegistry::Registrations::const_iterator it=_parent->mutation_parameters().function_registry().registrations().begin(); |
69 | 83 | it!=_parent->mutation_parameters().function_registry().registrations().end(); |
77 | 91 | #endif |
78 | 92 | if (c==-1 || fn.classification()&(1<<c)) |
79 | 93 | { |
80 | QGroupBox* g=new QGroupBox(3,Qt::Horizontal,fn.name(),scrollview->contentParent()); | |
94 | QGroupBox*const g=new QGroupBox(fn.name().c_str()); | |
95 | scrollarea->widget()->layout()->addWidget(g); | |
96 | g->setLayout(new QHBoxLayout); | |
81 | 97 | |
82 | 98 | QSizePolicy spx(QSizePolicy::Expanding,QSizePolicy::Preferred); |
83 | 99 | g->setSizePolicy(spx); |
84 | 100 | |
85 | new QLabel("2^-10",g); | |
86 | QSlider* s=new QSlider(-10,0,1,0,Qt::Horizontal,g); | |
101 | g->layout()->addWidget(new QLabel("2^-10")); | |
102 | QSlider*const s=new QSlider(Qt::Horizontal); | |
103 | g->layout()->addWidget(s); | |
104 | s->setMinimum(-10); | |
105 | s->setMaximum(0); | |
106 | s->setValue(0); | |
107 | s->setTickInterval(1); | |
108 | s->setTickPosition(QSlider::TicksBothSides); | |
87 | 109 | s->setSizePolicy(spx); |
88 | new QLabel("1",g); | |
110 | g->layout()->addWidget(new QLabel("1")); | |
89 | 111 | |
90 | 112 | _slider_to_function.insert(std::make_pair(s,&fn)); |
91 | 113 | |
113 | 135 | |
114 | 136 | // And add another tab for all the branching-ratio/dilution controls |
115 | 137 | { |
116 | QVBox* vbox=new QVBox(this); | |
138 | QWidget*const vbox=new QWidget; | |
139 | vbox->setLayout(new QVBoxLayout); | |
117 | 140 | tabs->addTab(vbox,"Dilution"); |
118 | 141 | |
119 | _branching_ratio=new QLabel(vbox); | |
142 | _branching_ratio=new QLabel; | |
143 | vbox->layout()->addWidget(_branching_ratio); | |
120 | 144 | |
121 | QGroupBox* c0=new QGroupBox(3,Qt::Horizontal,"Required branching ratio after dilution",vbox); | |
122 | new QLabel("0.1",c0); | |
123 | _slider_target_branching_ratio=new QSlider(10,90,1,50,Qt::Horizontal,c0); | |
124 | QToolTip::add(_slider_target_branching_ratio,"The branching ratio must be diluted to <1.0 to prevent formation of infinitely large function-trees.\nWarning: setting a high value results in complex function trees taking a long time to compute.\nSetting a low value results in very simple images."); | |
125 | new QLabel("0.9",c0); | |
126 | ||
127 | QGroupBox* c1=new QGroupBox(3,Qt::Horizontal,"Of diluting nodes, proportion constant:",vbox); | |
128 | new QLabel("0.0",c1); | |
129 | _slider_proportion_constant=new QSlider(0,100,1,50,Qt::Horizontal,c1); | |
130 | new QLabel("1.0",c1); | |
131 | QToolTip::add(_slider_proportion_constant,"This specifies the proportion of diluting nodes which will be constant."); | |
145 | QGroupBox*const c0=new QGroupBox("Required branching ratio after dilution"); | |
146 | c0->setLayout(new QHBoxLayout); | |
147 | vbox->layout()->addWidget(c0); | |
148 | ||
149 | c0->layout()->addWidget(new QLabel("0.1")); | |
150 | _slider_target_branching_ratio=new QSlider(Qt::Horizontal); | |
151 | c0->layout()->addWidget(_slider_target_branching_ratio); | |
152 | _slider_target_branching_ratio->setMinimum(10); | |
153 | _slider_target_branching_ratio->setMaximum(90); | |
154 | _slider_target_branching_ratio->setValue(50); | |
155 | _slider_target_branching_ratio->setTickInterval(10); | |
156 | _slider_target_branching_ratio->setTickPosition(QSlider::TicksBothSides); | |
157 | _slider_target_branching_ratio->setToolTip("The branching ratio must be diluted to <1.0 to prevent formation of infinitely large function-trees.\nWarning: setting a high value results in complex function trees taking a long time to compute.\nSetting a low value results in very simple images."); | |
158 | c0->layout()->addWidget(new QLabel("0.9")); | |
159 | ||
160 | QGroupBox*const c1=new QGroupBox("Of diluting nodes, proportion constant:"); | |
161 | c1->setLayout(new QHBoxLayout); | |
162 | vbox->layout()->addWidget(c1); | |
163 | c1->layout()->addWidget(new QLabel("0.0")); | |
164 | _slider_proportion_constant=new QSlider(Qt::Horizontal,c1); | |
165 | c1->layout()->addWidget(_slider_proportion_constant); | |
166 | _slider_proportion_constant->setMinimum(0); | |
167 | _slider_proportion_constant->setMaximum(100); | |
168 | _slider_proportion_constant->setValue(50); | |
169 | _slider_proportion_constant->setTickInterval(10); | |
170 | _slider_proportion_constant->setTickPosition(QSlider::TicksBothSides); | |
171 | _slider_proportion_constant->setToolTip("This specifies the proportion of diluting nodes which will be constant."); | |
172 | c1->layout()->addWidget(new QLabel("1.0")); | |
132 | 173 | |
133 | QGroupBox* c2=new QGroupBox(3,Qt::Horizontal,"Of non-constant diluting nodes, proportion transforms",vbox); | |
134 | new QLabel("0.0",c2); | |
135 | _slider_identity_supression=new QSlider(0,100,1,50,Qt::Horizontal,c2); | |
136 | QToolTip::add(_slider_identity_supression,"This specifies the proportion of non-constant diluting nodes which will be transforms (c.f identity nodes)."); | |
137 | new QLabel("1.0",c2); | |
174 | QGroupBox*const c2=new QGroupBox("Of non-constant diluting nodes, proportion transforms"); | |
175 | c2->setLayout(new QHBoxLayout); | |
176 | vbox->layout()->addWidget(c2); | |
177 | c2->layout()->addWidget(new QLabel("0.0")); | |
178 | _slider_identity_supression=new QSlider(Qt::Horizontal,c2); | |
179 | c2->layout()->addWidget(_slider_identity_supression); | |
180 | _slider_identity_supression->setMinimum(0); | |
181 | _slider_identity_supression->setMaximum(100); | |
182 | _slider_identity_supression->setValue(50); | |
183 | _slider_identity_supression->setTickInterval(10); | |
184 | _slider_identity_supression->setTickPosition(QSlider::TicksBothSides); | |
185 | _slider_identity_supression->setToolTip("This specifies the proportion of non-constant diluting nodes which will be transforms (c.f identity nodes)."); | |
186 | c2->layout()->addWidget(new QLabel("1.0")); | |
138 | 187 | |
139 | 188 | connect( |
140 | 189 | _slider_target_branching_ratio,SIGNAL(valueChanged(int)), |
142 | 191 | ); |
143 | 192 | |
144 | 193 | connect( |
145 | _ok,SIGNAL(clicked()), | |
194 | ok,SIGNAL(clicked()), | |
146 | 195 | this,SLOT(hide()) |
147 | 196 | ); |
148 | 197 | |
167 | 216 | |
168 | 217 | DialogFunctions::~DialogFunctions() |
169 | 218 | {} |
170 | ||
171 | void DialogFunctions::resizeEvent(QResizeEvent* e) | |
172 | { | |
173 | Superclass::resizeEvent(e); | |
174 | _dialog_content->resize(size()); | |
175 | } | |
176 | 219 | |
177 | 220 | void DialogFunctions::setup_from_mutation_parameters() |
178 | 221 | { |
261 | 304 | //std::clog << "[DialogFunctions::mutation_parameters_changed()]\n"; |
262 | 305 | setup_from_mutation_parameters(); |
263 | 306 | } |
264 |
21 | 21 | |
22 | 22 | #ifndef _dialog_functions_h_ |
23 | 23 | #define _dialog_functions_h_ |
24 | ||
25 | #include <qgrid.h> | |
26 | #include <qspinbox.h> | |
27 | #include <qslider.h> | |
28 | #include <qcheckbox.h> | |
29 | #include <qmainwindow.h> | |
30 | #include <qstatusbar.h> | |
31 | 24 | |
32 | 25 | #include "mutation_parameters_qobject.h" |
33 | 26 | |
85 | 78 | private: |
86 | 79 | Q_OBJECT |
87 | 80 | |
88 | typedef QDialog Superclass; | |
89 | ||
90 | 81 | protected: |
91 | 82 | //! Owner of dialog |
92 | 83 | EvolvotronMain*const _parent; |
97 | 88 | MutationParametersQObject*const _mutation_parameters; |
98 | 89 | |
99 | 90 | //! Top level holder of all the dialog content. |
100 | QVBox* _dialog_content; | |
91 | QWidget* _dialog_content; | |
101 | 92 | |
102 | 93 | //! Notification of undiluted branching ratio. |
103 | 94 | QLabel* _branching_ratio; |
114 | 105 | //! Lookup from each slider in the weighting controls area to corresponding function. |
115 | 106 | std::map<QSlider*,const FunctionRegistration*> _slider_to_function; |
116 | 107 | |
117 | //! Button to close dialog. | |
118 | QPushButton* _ok; | |
119 | ||
120 | //! Need to pass resizes on to vbox or things just get chopped. | |
121 | virtual void resizeEvent(QResizeEvent*); | |
122 | ||
123 | 108 | public: |
124 | 109 | //! Constructor. |
125 | 110 | DialogFunctions(EvolvotronMain* parent,MutationParametersQObject* mp); |
126 | 111 | |
127 | 112 | //! Destructor. |
128 | virtual ~DialogFunctions(); | |
113 | ~DialogFunctions(); | |
129 | 114 | |
130 | 115 | //! Reload from _mutation_parameters |
131 | 116 | void setup_from_mutation_parameters(); |
52 | 52 | "<h2>Mouse</h2>" |
53 | 53 | "<h3>Left-click</h3>" |
54 | 54 | "<p>Spawns mutant offspring.</p>" |
55 | "<h3>Middle-drag</h2>" | |
55 | "<h3>Middle-drag</h3>" | |
56 | 56 | "<ul>" |
57 | 57 | " <li>" |
58 | 58 | " Unmodified - pan" |
146 | 146 | DialogHelp::DialogHelp(QWidget* parent,bool full) |
147 | 147 | :QDialog(parent) |
148 | 148 | { |
149 | setCaption(full ? "Evolvotron User Manual" : "Evolvotron Quick Reference"); | |
150 | setMinimumSize(300,200); | |
149 | setWindowTitle(full ? "Evolvotron User Manual" : "Evolvotron Quick Reference"); | |
150 | setMinimumSize(480,360); | |
151 | setSizeGripEnabled(true); | |
151 | 152 | |
152 | _vbox=new QVBox(this); | |
153 | ||
154 | _browser=new QTextBrowser(_vbox); | |
155 | _browser->setText(full ? helptext_long : helptext_short); | |
153 | setLayout(new QVBoxLayout); | |
156 | 154 | |
157 | _ok=new QPushButton("OK",_vbox); | |
158 | // Setting this button to default doesn't seem to have an effect (it does in other browsers). | |
159 | // Something to do with sharing with a QTextBrowser ? | |
160 | _ok->setDefault(true); | |
155 | QTextBrowser*const browser=new QTextBrowser; | |
156 | layout()->addWidget(browser); | |
157 | browser->setText(full ? helptext_long : helptext_short); | |
161 | 158 | |
162 | connect( | |
163 | _ok,SIGNAL(clicked()), | |
164 | this,SLOT(hide()) | |
165 | ); | |
159 | QPushButton*const ok=new QPushButton("OK"); | |
160 | layout()->addWidget(ok); | |
161 | ok->setDefault(true); | |
162 | ||
163 | connect | |
164 | ( | |
165 | ok,SIGNAL(clicked()), | |
166 | this,SLOT(hide()) | |
167 | ); | |
166 | 168 | } |
167 | 169 | |
168 | void DialogHelp::resizeEvent(QResizeEvent*) | |
169 | { | |
170 | _vbox->resize(size()); | |
171 | } | |
170 | DialogHelp::~DialogHelp() | |
171 | {} |
22 | 22 | #ifndef _dialog_help_h_ |
23 | 23 | #define _dialog_help_h_ |
24 | 24 | |
25 | #include <qtextbrowser.h> | |
26 | ||
27 | 25 | //! Provides a dialog box with some user documentation. |
28 | 26 | /*! More of a quick reference guide than a manual. |
29 | 27 | */ |
33 | 31 | Q_OBJECT |
34 | 32 | |
35 | 33 | public: |
34 | ||
36 | 35 | //! Constructor. |
37 | 36 | DialogHelp(QWidget* parent,bool full); |
38 | 37 | |
39 | 38 | //! Destructor. |
40 | virtual ~DialogHelp() | |
41 | {} | |
42 | ||
43 | protected: | |
44 | //! Vertical layout. | |
45 | QVBox* _vbox; | |
46 | ||
47 | //! Label for name/release/author etc | |
48 | QTextBrowser* _browser; | |
49 | ||
50 | //! Button to close dialog. | |
51 | QPushButton* _ok; | |
52 | ||
53 | //! Need to pass resizes on to vbox or things just get chopped. | |
54 | virtual void resizeEvent(QResizeEvent*); | |
39 | ~DialogHelp(); | |
55 | 40 | }; |
56 | 41 | |
57 | ||
58 | ||
59 | 42 | #endif |
24 | 24 | #include "dialog_mutatable_image_display.h" |
25 | 25 | |
26 | 26 | DialogMutatableImageDisplay::DialogMutatableImageDisplay(QWidget* parent) |
27 | :QDialog(parent,0,TRUE) | |
27 | :QDialog(parent) | |
28 | 28 | { |
29 | setCaption("Image Properties"); | |
30 | setMinimumSize(320,240); | |
29 | setWindowTitle("Image Properties"); | |
30 | setSizeGripEnabled(true); | |
31 | 31 | |
32 | _vbox=new QVBox(this); | |
32 | setLayout(new QVBoxLayout); | |
33 | 33 | |
34 | _tabs=new QTabWidget(_vbox); | |
34 | _tabs=new QTabWidget; | |
35 | layout()->addWidget(_tabs); | |
35 | 36 | |
36 | _label_info=new QLabel(QString(""),_tabs); | |
37 | _label_info=new QLabel(QString("")); | |
37 | 38 | _tabs->addTab(_label_info,"Summary"); |
38 | 39 | |
39 | _textedit_xml=new QTextEdit(_tabs); | |
40 | _textedit_xml=new QTextEdit; | |
40 | 41 | _textedit_xml->setReadOnly(true); |
41 | _textedit_xml->setTextFormat(PlainText); | |
42 | 42 | _tabs->addTab(_textedit_xml,"Detail"); |
43 | 43 | |
44 | _ok=new QPushButton("OK",_vbox); | |
44 | _ok=new QPushButton("OK"); | |
45 | 45 | _ok->setDefault(true); |
46 | layout()->addWidget(_ok); | |
46 | 47 | |
47 | 48 | connect( |
48 | 49 | _ok,SIGNAL(clicked()), |
50 | 51 | ); |
51 | 52 | } |
52 | 53 | |
53 | void DialogMutatableImageDisplay::resizeEvent(QResizeEvent*) | |
54 | { | |
55 | _vbox->resize(size()); | |
56 | } | |
54 | DialogMutatableImageDisplay::~DialogMutatableImageDisplay() | |
55 | {} | |
57 | 56 | |
58 | 57 | void DialogMutatableImageDisplay::set_content(const std::string& m,const std::string& x) |
59 | 58 | { |
60 | 59 | _label_info->setText(QString(m.c_str())); |
61 | 60 | _label_info->adjustSize(); |
62 | 61 | |
63 | _textedit_xml->setText(x); | |
62 | _textedit_xml->setPlainText(x.c_str()); | |
64 | 63 | |
65 | 64 | adjustSize(); |
66 | 65 | updateGeometry(); |
67 | 66 | } |
68 |
34 | 34 | |
35 | 35 | protected: |
36 | 36 | |
37 | //! Vertical layout. | |
38 | QVBox* _vbox; | |
39 | ||
40 | 37 | //! Tabs for info and xml (summary and detail) |
41 | 38 | QTabWidget* _tabs; |
42 | 39 | |
54 | 51 | DialogMutatableImageDisplay(QWidget* parent); |
55 | 52 | |
56 | 53 | //! Destructor. |
57 | virtual ~DialogMutatableImageDisplay() | |
58 | {} | |
59 | ||
60 | //! Need to pass resizes on to vbox or things just get chopped. | |
61 | virtual void resizeEvent(QResizeEvent*); | |
54 | ~DialogMutatableImageDisplay(); | |
62 | 55 | |
63 | 56 | //! Set content of main text and scrolling area. |
64 | 57 | void set_content(const std::string& m,const std::string& x); |
0 | 0 | // Source file for evolvotron |
1 | // Copyright (C) 2002,2003,2004 Tim Day | |
1 | // Copyright (C) 2009 Tim Day | |
2 | 2 | /* |
3 | 3 | This program is free software; you can redistribute it and/or |
4 | 4 | modify it under the terms of the GNU General Public License |
31 | 31 | { |
32 | 32 | assert(_parent!=0); |
33 | 33 | |
34 | setCaption("Mutation Parameters"); | |
35 | ||
36 | _dialog_content=new QVBox(this); | |
37 | ||
38 | _tabs=new QTabWidget(_dialog_content); | |
39 | ||
40 | _vbox_base_mutation=new QVBox(_tabs); | |
34 | setWindowTitle("Mutation Parameters"); | |
35 | setSizeGripEnabled(true); | |
36 | ||
37 | setLayout(new QVBoxLayout); | |
38 | ||
39 | _tabs=new QTabWidget(); | |
40 | layout()->addWidget(_tabs); | |
41 | ||
42 | _vbox_base_mutation=new QWidget; | |
43 | _vbox_base_mutation->setLayout(new QVBoxLayout); | |
41 | 44 | _tabs->addTab(_vbox_base_mutation,"Base"); |
42 | 45 | |
43 | _grid_buttons=new QGrid(5,Qt::Horizontal,_vbox_base_mutation); | |
44 | ||
45 | _button_reset=new QPushButton("&Reset",_grid_buttons); | |
46 | _button_cool=new QPushButton("&Cool",_grid_buttons); | |
47 | _button_shield=new QPushButton("&Shield",_grid_buttons); | |
48 | _button_heat=new QPushButton("&Heat",_grid_buttons); | |
49 | _button_irradiate=new QPushButton("&Irradiate",_grid_buttons); | |
50 | ||
51 | QToolTip::add(_button_cool,"Decrease size of constant perturbations during mutation."); | |
52 | QToolTip::add(_button_heat,"Increase size of constant perturbations during mutation."); | |
53 | QToolTip::add(_button_shield,"Decrease probability of function tree structural mutations."); | |
54 | QToolTip::add(_button_irradiate,"Increase probability of function tree structural mutations."); | |
46 | _grid_buttons=new QWidget; | |
47 | _vbox_base_mutation->layout()->addWidget(_grid_buttons); | |
48 | ||
49 | QGridLayout*const grid_buttons_layout=new QGridLayout(); | |
50 | _grid_buttons->setLayout(grid_buttons_layout); | |
51 | ||
52 | grid_buttons_layout->addWidget(_button_reset=new QPushButton("&Reset",_grid_buttons),0,0); | |
53 | grid_buttons_layout->addWidget(_button_cool=new QPushButton("&Cool",_grid_buttons),0,1); | |
54 | grid_buttons_layout->addWidget(_button_shield=new QPushButton("&Shield",_grid_buttons),0,2); | |
55 | grid_buttons_layout->addWidget(_button_heat=new QPushButton("&Heat",_grid_buttons),0,3); | |
56 | grid_buttons_layout->addWidget(_button_irradiate=new QPushButton("&Irradiate",_grid_buttons),0,4); | |
57 | ||
58 | _button_cool->setToolTip("Decrease size of constant perturbations during mutation."); | |
59 | _button_heat->setToolTip("Increase size of constant perturbations during mutation."); | |
60 | _button_shield->setToolTip("Decrease probability of function tree structural mutations."); | |
61 | _button_irradiate->setToolTip("Increase probability of function tree structural mutations."); | |
55 | 62 | |
56 | 63 | connect(_button_reset, SIGNAL(clicked()),this,SLOT(reset())); |
57 | 64 | connect(_button_cool, SIGNAL(clicked()),this,SLOT(cool())); |
59 | 66 | connect(_button_shield, SIGNAL(clicked()),this,SLOT(shield())); |
60 | 67 | connect(_button_irradiate,SIGNAL(clicked()),this,SLOT(irradiate())); |
61 | 68 | |
62 | _vbox_autocool=new QVBox(_tabs); | |
69 | _vbox_autocool=new QWidget; | |
70 | _vbox_autocool->setLayout(new QVBoxLayout); | |
63 | 71 | _tabs->addTab(_vbox_autocool,"Autocool"); |
64 | 72 | |
65 | _grid_base_mutation=new QGrid(2,Qt::Horizontal,_vbox_base_mutation); | |
66 | _grid_autocool=new QGrid(2,Qt::Horizontal,_vbox_autocool); | |
73 | _grid_base_mutation=new QWidget; | |
74 | _vbox_base_mutation->layout()->addWidget(_grid_base_mutation); | |
75 | ||
76 | QGridLayout*const grid_base_mutation_layout=new QGridLayout(); | |
77 | _grid_base_mutation->setLayout(grid_base_mutation_layout); | |
78 | ||
79 | grid_base_mutation_layout->addWidget(new QLabel("Perturbation magnitude:"),0,0); | |
80 | grid_base_mutation_layout->addWidget(_spinbox_magnitude=new QSpinBox,0,1); | |
81 | _spinbox_magnitude->setRange(0,_scale); | |
82 | _spinbox_magnitude->setSingleStep(maximum(1,_scale/1000)); | |
83 | _spinbox_magnitude->setSuffix(QString("/%1").arg(_scale)); | |
84 | _spinbox_magnitude->setToolTip("Scale of function parameter perturbations."); | |
67 | 85 | |
68 | new QLabel("Perturbation magnitude:",_grid_base_mutation); | |
69 | _spinbox_magnitude=new QSpinBox(0,_scale,maximum(1,_scale/100),_grid_base_mutation); | |
70 | _spinbox_magnitude->setSuffix(QString("/%1").arg(_scale)); | |
71 | QToolTip::add(_spinbox_magnitude,"Scale of function parameter perturbations."); | |
72 | ||
73 | new QLabel("p(Parameter reset)",_grid_base_mutation); | |
74 | _spinbox_parameter_reset=new QSpinBox(0,_scale,maximum(1,_scale/1000),_grid_base_mutation); | |
86 | grid_base_mutation_layout->addWidget(new QLabel("p(Parameter reset)"),1,0); | |
87 | grid_base_mutation_layout->addWidget(_spinbox_parameter_reset=new QSpinBox,1,1); | |
88 | _spinbox_parameter_reset->setRange(0,_scale); | |
89 | _spinbox_parameter_reset->setSingleStep(maximum(1,_scale/1000)); | |
75 | 90 | _spinbox_parameter_reset->setSuffix(QString("/%1").arg(_scale)); |
76 | QToolTip::add(_spinbox_parameter_reset,"Probability of function parameters being completely reset."); | |
77 | ||
78 | new QLabel("p(Glitch)",_grid_base_mutation); | |
79 | _spinbox_glitch=new QSpinBox(0,_scale,maximum(1,_scale/1000),_grid_base_mutation); | |
91 | _spinbox_parameter_reset->setToolTip("Probability of function parameters being completely reset."); | |
92 | ||
93 | grid_base_mutation_layout->addWidget(new QLabel("p(Glitch)"),2,0); | |
94 | grid_base_mutation_layout->addWidget(_spinbox_glitch=new QSpinBox,2,1); | |
95 | _spinbox_glitch->setRange(0,_scale); | |
96 | _spinbox_glitch->setSingleStep(maximum(1,_scale/1000)); | |
80 | 97 | _spinbox_glitch->setSuffix(QString("/%1").arg(_scale)); |
81 | QToolTip::add(_spinbox_glitch,"Probability of function branch being replaced by new random stub."); | |
82 | ||
83 | new QLabel("p(Shuffle)",_grid_base_mutation); | |
84 | _spinbox_shuffle=new QSpinBox(0,_scale,maximum(1,_scale/1000),_grid_base_mutation); | |
98 | _spinbox_glitch->setToolTip("Probability of function branch being replaced by new random stub."); | |
99 | ||
100 | grid_base_mutation_layout->addWidget(new QLabel("p(Shuffle)"),3,0); | |
101 | grid_base_mutation_layout->addWidget(_spinbox_shuffle=new QSpinBox,3,1); | |
102 | _spinbox_shuffle->setRange(0,_scale); | |
103 | _spinbox_shuffle->setSingleStep(maximum(1,_scale/1000)); | |
85 | 104 | _spinbox_shuffle->setSuffix(QString("/%1").arg(_scale)); |
86 | QToolTip::add(_spinbox_shuffle,"Probability of function branches being reordered."); | |
87 | ||
88 | new QLabel("p(Insert)",_grid_base_mutation); | |
89 | _spinbox_insert=new QSpinBox(0,_scale,maximum(1,_scale/1000),_grid_base_mutation); | |
105 | _spinbox_shuffle->setToolTip("Probability of function branches being reordered."); | |
106 | ||
107 | grid_base_mutation_layout->addWidget(new QLabel("p(Insert)"),4,0); | |
108 | grid_base_mutation_layout->addWidget(_spinbox_insert=new QSpinBox,4,1); | |
109 | _spinbox_insert->setRange(0,_scale); | |
110 | _spinbox_insert->setSingleStep(maximum(1,_scale/1000)); | |
90 | 111 | _spinbox_insert->setSuffix(QString("/%1").arg(_scale)); |
91 | QToolTip::add(_spinbox_insert,"Probability of function branch having random stub inserted."); | |
92 | ||
93 | new QLabel("p(Substitute)",_grid_base_mutation); | |
94 | _spinbox_substitute=new QSpinBox(0,_scale,maximum(1,_scale/1000),_grid_base_mutation); | |
112 | _spinbox_insert->setToolTip("Probability of function branch having random stub inserted."); | |
113 | ||
114 | grid_base_mutation_layout->addWidget(new QLabel("p(Substitute)"),5,0); | |
115 | grid_base_mutation_layout->addWidget(_spinbox_substitute=new QSpinBox,5,1); | |
116 | _spinbox_substitute->setRange(0,_scale); | |
117 | _spinbox_substitute->setSingleStep(maximum(1,_scale/1000)); | |
95 | 118 | _spinbox_substitute->setSuffix(QString("/%1").arg(_scale)); |
96 | QToolTip::add(_spinbox_substitute,"Probability of function node's type being changed."); | |
97 | ||
98 | new QLabel("Enable",_grid_autocool); | |
99 | _checkbox_autocool_enable=new QCheckBox(_grid_autocool); | |
100 | QToolTip::add(_checkbox_autocool_enable,"Autocooling reduces the strength and probablility of mutations with increasing numbers of generations."); | |
101 | ||
102 | new QLabel("Half-life",_grid_autocool); | |
103 | _spinbox_autocool_halflife=new QSpinBox(1,1000,1,_grid_autocool); | |
104 | QToolTip::add(_spinbox_autocool_halflife,"Number of generations needed to halve mutation influence when autocooling."); | |
105 | ||
106 | _label_autocool_generations=new QLabel("",_grid_autocool); | |
107 | ||
108 | _button_autocool_reheat=new QPushButton("Reheat",_grid_autocool); | |
119 | _spinbox_substitute->setToolTip("Probability of function node's type being changed."); | |
120 | ||
121 | _grid_autocool=new QWidget; | |
122 | _vbox_autocool->layout()->addWidget(_grid_autocool); | |
123 | QGridLayout*const grid_autocool_layout=new QGridLayout(); | |
124 | _grid_autocool->setLayout(grid_autocool_layout); | |
125 | ||
126 | grid_autocool_layout->addWidget(_checkbox_autocool_enable=new QCheckBox("Enable autocool"),0,1); | |
127 | _checkbox_autocool_enable->setToolTip("Autocooling reduces the strength and probablility of mutations with increasing numbers of generations."); | |
128 | ||
129 | grid_autocool_layout->addWidget(new QLabel("Half-life"),1,0); | |
130 | grid_autocool_layout->addWidget(_spinbox_autocool_halflife=new QSpinBox,1,1); | |
131 | _spinbox_autocool_halflife->setRange(1,1000); | |
132 | _spinbox_autocool_halflife->setSingleStep(1); | |
133 | _spinbox_autocool_halflife->setToolTip("Number of generations needed to halve mutation influence when autocooling."); | |
134 | ||
135 | grid_autocool_layout->addWidget(_label_autocool_generations=new QLabel(""),2,0); | |
136 | ||
137 | grid_autocool_layout->addWidget(_button_autocool_reheat=new QPushButton("Reheat"),2,1); | |
109 | 138 | connect(_button_autocool_reheat,SIGNAL(clicked()),this,SLOT(reheat())); |
110 | 139 | |
111 | 140 | setup_from_mutation_parameters(); |
122 | 151 | connect(_checkbox_autocool_enable,SIGNAL(stateChanged(int)),this,SLOT(changed_autocool_enable(int))); |
123 | 152 | connect(_spinbox_autocool_halflife,SIGNAL(valueChanged(int)),this,SLOT(changed_autocool_halflife(int))); |
124 | 153 | |
125 | _ok=new QPushButton("OK",_dialog_content); | |
154 | _ok=new QPushButton("OK"); | |
155 | layout()->addWidget(_ok); | |
126 | 156 | _ok->setDefault(true); |
127 | 157 | |
128 | 158 | connect( |
136 | 166 | ); |
137 | 167 | } |
138 | 168 | |
139 | void DialogMutationParameters::resizeEvent(QResizeEvent* e) | |
140 | { | |
141 | Superclass::resizeEvent(e); | |
142 | _dialog_content->resize(size()); | |
143 | } | |
169 | DialogMutationParameters::~DialogMutationParameters() | |
170 | {} | |
144 | 171 | |
145 | 172 | void DialogMutationParameters::setup_from_mutation_parameters() |
146 | 173 | { |
201 | 228 | |
202 | 229 | void DialogMutationParameters::changed_autocool_enable(int buttonstate) |
203 | 230 | { |
204 | if (buttonstate==QButton::On) _mutation_parameters->autocool_enable(true); | |
205 | else if (buttonstate==QButton::Off) _mutation_parameters->autocool_enable(false); | |
231 | if (buttonstate==Qt::Checked) _mutation_parameters->autocool_enable(true); | |
232 | else if (buttonstate==Qt::Unchecked) _mutation_parameters->autocool_enable(false); | |
206 | 233 | } |
207 | 234 | |
208 | 235 | void DialogMutationParameters::changed_magnitude(int v) |
45 | 45 | */ |
46 | 46 | MutationParametersQObject*const _mutation_parameters; |
47 | 47 | |
48 | //! Top level holder of all the dialog content. | |
49 | QVBox* _dialog_content; | |
50 | ||
51 | 48 | //! Tabs for base parameters and autocool |
52 | 49 | QTabWidget* _tabs; |
53 | 50 | |
54 | 51 | //! Tab for base mutation parameter controls |
55 | QVBox* _vbox_base_mutation; | |
52 | QWidget* _vbox_base_mutation; | |
56 | 53 | |
57 | 54 | //! Grid for buttons; |
58 | QGrid* _grid_buttons; | |
55 | QWidget* _grid_buttons; | |
59 | 56 | |
60 | 57 | //! Grid for base parameter control spinners |
61 | QGrid* _grid_base_mutation; | |
58 | QWidget* _grid_base_mutation; | |
62 | 59 | |
63 | 60 | //! Group for autocool parameters |
64 | QVBox* _vbox_autocool; | |
61 | QWidget* _vbox_autocool; | |
65 | 62 | |
66 | 63 | //! Grid for autocool parameters |
67 | QGrid* _grid_autocool; | |
64 | QWidget* _grid_autocool; | |
68 | 65 | |
69 | 66 | //! Label to show number of generations |
70 | 67 | QLabel* _label_autocool_generations; |
98 | 95 | //! Button to close dialog. |
99 | 96 | QPushButton* _ok; |
100 | 97 | |
101 | //! Need to pass resizes on to vbox or things just get chopped. | |
102 | virtual void resizeEvent(QResizeEvent*); | |
103 | ||
104 | 98 | //! Reload spinboxes from _mutation_parameters. |
105 | 99 | void setup_from_mutation_parameters(); |
106 | 100 | |
109 | 103 | DialogMutationParameters(QMainWindow* parent,MutationParametersQObject* mp); |
110 | 104 | |
111 | 105 | //! Destructor. |
112 | virtual ~DialogMutationParameters() | |
113 | {} | |
106 | ~DialogMutationParameters(); | |
114 | 107 | |
115 | 108 | public slots: |
116 | 109 |
27 | 27 | :QDialog(parent) |
28 | 28 | ,_render_parameters(rp) |
29 | 29 | { |
30 | setCaption("Render Parameters"); | |
30 | setWindowTitle("Render Parameters"); | |
31 | setSizeGripEnabled(true); | |
31 | 32 | |
32 | _dialog_content=new QVBox(this); | |
33 | setLayout(new QVBoxLayout); | |
33 | 34 | |
34 | _grid=new QGrid(2,Qt::Horizontal,_dialog_content); | |
35 | layout()->addWidget(_checkbox_jittered_samples=new QCheckBox("Jittered samples")); | |
36 | _checkbox_jittered_samples->setToolTip("Jitter moves sampling positions randomly within a pixel. This helps to break up aliasing and moire patterns."); | |
35 | 37 | |
36 | new QLabel("Jittered samples",_grid); | |
37 | _checkbox_jittered_samples=new QCheckBox(_grid); | |
38 | QToolTip::add(_checkbox_jittered_samples,"Jitter moves sampling positions randomly within a pixel. This helps to break up aliasing and moire patterns."); | |
38 | _buttonvbox=new QGroupBox("Oversampling (antialiasing)"); | |
39 | _buttonvbox->setLayout(new QVBoxLayout); | |
40 | layout()->addWidget(_buttonvbox); | |
41 | ||
42 | QRadioButton* button[4]; | |
43 | _buttonvbox->layout()->addWidget(button[0]=new QRadioButton("1x1")); | |
44 | _buttonvbox->layout()->addWidget(button[1]=new QRadioButton("2x2")); | |
45 | _buttonvbox->layout()->addWidget(button[2]=new QRadioButton("3x3")); | |
46 | _buttonvbox->layout()->addWidget(button[3]=new QRadioButton("4x4")); | |
39 | 47 | |
40 | _buttongroup=new QVButtonGroup("Oversampling (antialiasing)",_dialog_content); | |
41 | _buttongroup->insert(new QRadioButton("1x1",_buttongroup),1); | |
42 | _buttongroup->insert(new QRadioButton("2x2",_buttongroup),2); | |
43 | _buttongroup->insert(new QRadioButton("3x3",_buttongroup),3); | |
44 | _buttongroup->insert(new QRadioButton("4x4",_buttongroup),4); | |
45 | _buttongroup->setRadioButtonExclusive(true); | |
46 | QToolTip::add(_buttongroup->find(1),"No oversampling"); | |
47 | QToolTip::add(_buttongroup->find(2),"Enables a final antialiased rendering with 4 samples per pixel"); | |
48 | QToolTip::add(_buttongroup->find(3),"Enables a final antialiased rendering with 3 samples per pixel"); | |
49 | QToolTip::add(_buttongroup->find(4),"Enables a final antialiased rendering with 16 samples per pixel"); | |
48 | button[0]->setToolTip("No oversampling"); | |
49 | button[1]->setToolTip("Enables a final antialiased rendering with 4 samples per pixel"); | |
50 | button[2]->setToolTip("Enables a final antialiased rendering with 9 samples per pixel"); | |
51 | button[3]->setToolTip("Enables a final antialiased rendering with 16 samples per pixel"); | |
52 | ||
53 | _buttongroup=new QButtonGroup(_buttonvbox); | |
54 | _buttongroup->addButton(button[0],1); | |
55 | _buttongroup->addButton(button[1],2); | |
56 | _buttongroup->addButton(button[2],3); | |
57 | _buttongroup->addButton(button[3],4); | |
50 | 58 | |
51 | 59 | setup_from_render_parameters(); |
52 | 60 | |
53 | 61 | connect(_checkbox_jittered_samples,SIGNAL(stateChanged(int)),this,SLOT(changed_jittered_samples(int))); |
54 | connect(_buttongroup,SIGNAL(clicked(int)),this,SLOT(changed_oversampling(int))); | |
62 | connect(_buttongroup,SIGNAL(buttonClicked(int)),this,SLOT(changed_oversampling(int))); | |
55 | 63 | |
56 | _ok=new QPushButton("OK",_dialog_content); | |
64 | _ok=new QPushButton("OK"); | |
57 | 65 | _ok->setDefault(true); |
66 | layout()->addWidget(_ok); | |
58 | 67 | |
59 | 68 | connect( |
60 | 69 | _ok,SIGNAL(clicked()), |
67 | 76 | ); |
68 | 77 | } |
69 | 78 | |
70 | void DialogRenderParameters::resizeEvent(QResizeEvent* e) | |
71 | { | |
72 | Superclass::resizeEvent(e); | |
73 | _dialog_content->resize(size()); | |
74 | } | |
79 | DialogRenderParameters::~DialogRenderParameters() | |
80 | {} | |
75 | 81 | |
76 | 82 | void DialogRenderParameters::setup_from_render_parameters() |
77 | 83 | { |
78 | 84 | _checkbox_jittered_samples->setChecked(_render_parameters->jittered_samples()); |
79 | 85 | |
80 | QButton*const which_button=_buttongroup->find(_render_parameters->multisample_grid()); | |
86 | QAbstractButton*const which_button=_buttongroup->button(_render_parameters->multisample_grid()); | |
81 | 87 | if (which_button) |
82 | 88 | { |
83 | _buttongroup->setButton(_buttongroup->id(which_button)); | |
89 | which_button->click(); | |
84 | 90 | } |
85 | 91 | } |
86 | 92 | |
87 | 93 | void DialogRenderParameters::changed_jittered_samples(int buttonstate) |
88 | 94 | { |
89 | if (buttonstate==QButton::On) _render_parameters->jittered_samples(true); | |
90 | else if (buttonstate==QButton::Off) _render_parameters->jittered_samples(false); | |
95 | if (buttonstate==Qt::Checked) _render_parameters->jittered_samples(true); | |
96 | else if (buttonstate==Qt::Unchecked) _render_parameters->jittered_samples(false); | |
91 | 97 | } |
92 | 98 | |
93 | 99 | void DialogRenderParameters::changed_oversampling(int id) |
30 | 30 | private: |
31 | 31 | Q_OBJECT |
32 | 32 | |
33 | typedef QDialog Superclass; | |
34 | ||
35 | 33 | protected: |
36 | 34 | |
37 | 35 | //! Instance of MutationParameters under dialog control. |
40 | 38 | */ |
41 | 39 | RenderParameters*const _render_parameters; |
42 | 40 | |
43 | //! Top level holder of all the dialog content. | |
44 | QVBox* _dialog_content; | |
45 | ||
46 | //! Grid for buttons etc; | |
47 | QGrid* _grid; | |
48 | ||
49 | 41 | //! Enables jittered samples. |
50 | 42 | QCheckBox* _checkbox_jittered_samples; |
51 | 43 | |
52 | 44 | //! Chooses between multisampling levels. |
53 | QVButtonGroup* _buttongroup; | |
45 | QWidget* _buttonvbox; | |
46 | ||
47 | //! Chooses between multisampling levels. | |
48 | QButtonGroup* _buttongroup; | |
54 | 49 | |
55 | 50 | //! Button to close dialog. |
56 | 51 | QPushButton* _ok; |
57 | ||
58 | //! Need to pass resizes on to vbox or things just get chopped. | |
59 | virtual void resizeEvent(QResizeEvent*); | |
60 | 52 | |
61 | 53 | //! Reload from _render_parameters. |
62 | 54 | void setup_from_render_parameters(); |
66 | 58 | DialogRenderParameters(QMainWindow* parent,RenderParameters* rp); |
67 | 59 | |
68 | 60 | //! Destructor. |
69 | virtual ~DialogRenderParameters() | |
70 | {} | |
61 | ~DialogRenderParameters(); | |
71 | 62 | |
72 | 63 | public slots: |
73 | 64 |
192 | 192 | uint multisample_level, |
193 | 193 | bool function_debug_mode |
194 | 194 | ) |
195 | :QMainWindow(parent,0,Qt::WType_TopLevel|Qt::WDestructiveClose) | |
195 | :QMainWindow(parent) | |
196 | 196 | ,_history(new EvolvotronMain::History(this)) |
197 | 197 | ,_mutation_parameters(time(0),autocool,function_debug_mode,this) |
198 | 198 | ,_render_parameters(jitter,multisample_level,this) |
200 | 200 | ,_statusbar_tasks_enlargement(0) |
201 | 201 | ,_last_spawn_method(&EvolvotronMain::spawn_normal) |
202 | 202 | { |
203 | setMinimumSize(600,400); | |
203 | setAttribute(Qt::WA_DeleteOnClose,true); | |
204 | setAttribute(Qt::WA_QuitOnClose,true); | |
205 | ||
206 | setMinimumSize(640,480); | |
204 | 207 | |
205 | 208 | // Need to create this first or DialogMutationParameters might cause one to be created too. |
206 | _statusbar=new QStatusBar(this); | |
207 | _statusbar->setSizeGripEnabled(false); | |
208 | ||
209 | _statusbar_tasks_label=new QLabel("Ready",_statusbar); | |
210 | _statusbar->addWidget(_statusbar_tasks_label,0,true); | |
209 | _statusbar=new QStatusBar; | |
210 | _statusbar->setSizeGripEnabled(true); | |
211 | setStatusBar(_statusbar); | |
212 | ||
213 | _statusbar->addWidget(_statusbar_tasks_label=new QLabel("Ready")); | |
211 | 214 | |
212 | 215 | _dialog_about=new DialogAbout(this,n_threads,separate_farm_for_enlargements); |
213 | 216 | _dialog_help_short=new DialogHelp(this,false); |
221 | 224 | |
222 | 225 | _dialog_favourite=new DialogFavourite(this); |
223 | 226 | |
224 | _menubar=new QMenuBar(this); | |
225 | ||
226 | _popupmenu_file=new QPopupMenu; | |
227 | _popupmenu_file->insertItem("Re&set (Reset mutation parameters, clear locks)",this,SLOT(reset_cold())); | |
228 | _popupmenu_file->insertItem("&Restart (Preserve mutation parameters and locks)",this,SLOT(reset_warm())); | |
229 | _popupmenu_file->insertItem("Remi&x (Randomize function weights and restart)",this,SLOT(reset_randomized())); | |
230 | _popupmenu_file->insertSeparator(); | |
231 | _popupmenu_file->insertItem("&Quit",qApp,SLOT(quit())); | |
232 | _menubar->insertItem("&File",_popupmenu_file); | |
233 | ||
234 | _popupmenu_edit=new QPopupMenu; | |
235 | _popupmenu_edit_undo_id=_popupmenu_edit->insertItem("&Undo",this,SLOT(undo())); | |
236 | _popupmenu_edit->setItemEnabled(_popupmenu_edit_undo_id,false); | |
237 | _popupmenu_edit->insertSeparator(); | |
238 | _popupmenu_edit->insertItem("&Simplify all functions",this,SLOT(simplify_constants())); | |
239 | _menubar->insertItem("&Edit",_popupmenu_edit); | |
240 | ||
241 | _popupmenu_settings=new QPopupMenu; | |
242 | ||
243 | // We want to use a checkmark on some items | |
244 | _popupmenu_settings->setCheckable(true); | |
245 | ||
246 | _popupmenu_settings->insertItem("Mutation ¶meters...",_dialog_mutation_parameters,SLOT(show())); | |
247 | _popupmenu_settings->insertItem("&Function weightings...",_dialog_functions,SLOT(show())); | |
248 | _popupmenu_settings->insertItem("Fa&vourite function...",_dialog_favourite,SLOT(show())); | |
249 | ||
250 | _popupmenu_settings->insertSeparator(); | |
251 | ||
252 | _popupmenu_settings->insertItem("Ren&der parameters...",_dialog_render_parameters,SLOT(show())); | |
253 | ||
254 | _popupmenu_settings->insertSeparator(); | |
255 | ||
256 | _menu_item_number_fullscreen=_popupmenu_settings->insertItem("Full&screen",this,SLOT(toggle_fullscreen())); | |
257 | _menu_item_number_hide_menu=_popupmenu_settings->insertItem("Hide &menu and statusbar",this,SLOT(toggle_hide_menu())); | |
258 | ||
259 | _popupmenu_settings->setItemChecked(_menu_item_number_fullscreen,start_fullscreen); | |
260 | _popupmenu_settings->setItemChecked(_menu_item_number_hide_menu,start_menuhidden); | |
261 | ||
262 | _menubar->insertItem("Se&ttings",_popupmenu_settings); | |
227 | _popupmenu_file=menuBar()->addMenu("&File"); | |
228 | _popupmenu_file->addAction("Reset (Reset mutation parameters, clear locks)",this,SLOT(reset_cold()),QKeySequence("r")); | |
229 | _popupmenu_file->addAction("Restart (Preserve mutation parameters and locks)",this,SLOT(reset_warm()),QKeySequence("t")); | |
230 | _popupmenu_file->addAction("Remix (Randomize function weights and restart)",this,SLOT(reset_randomized()),QKeySequence("x")); | |
231 | _popupmenu_file->addSeparator(); | |
232 | _popupmenu_file->addAction("Quit",qApp,SLOT(quit()),QKeySequence("q")); | |
233 | ||
234 | _popupmenu_edit=menuBar()->addMenu("&Edit"); | |
235 | _popupmenu_edit_undo_action=_popupmenu_edit->addAction("Undo",this,SLOT(undo()),QKeySequence("u")); | |
236 | _popupmenu_edit_undo_action->setEnabled(false); | |
237 | _popupmenu_edit->addSeparator(); | |
238 | _popupmenu_edit->addAction("Simplify all functions",this,SLOT(simplify_constants())); | |
239 | ||
240 | _popupmenu_settings=menuBar()->addMenu("Se&ttings"); | |
241 | _popupmenu_settings->addAction("Mutation parameters...",_dialog_mutation_parameters,SLOT(show())); | |
242 | _popupmenu_settings->addAction("Function weightings...",_dialog_functions,SLOT(show())); | |
243 | _popupmenu_settings->addAction("Favourite function...",_dialog_favourite,SLOT(show())); | |
244 | ||
245 | _popupmenu_settings->addSeparator(); | |
246 | ||
247 | _popupmenu_settings->addAction("Render parameters...",_dialog_render_parameters,SLOT(show())); | |
248 | ||
249 | _popupmenu_settings->addSeparator(); | |
250 | ||
251 | _menu_action_fullscreen=_popupmenu_settings->addAction("Fullscreen",this,SLOT(toggle_fullscreen()),QKeySequence("f")); | |
252 | _menu_action_fullscreen->setCheckable(true); | |
253 | _menu_action_fullscreen->setChecked(start_fullscreen); | |
254 | _menu_action_hide_menu=_popupmenu_settings->addAction("Hide menu and statusbar",this,SLOT(toggle_hide_menu()),QKeySequence("m")); | |
255 | _menu_action_hide_menu->setCheckable(true); | |
256 | _menu_action_hide_menu->setChecked(start_menuhidden); | |
263 | 257 | |
264 | 258 | //! This doesn't seem to do anything (supposed to push help menu over to far end ?) |
265 | _menubar->insertSeparator(); | |
266 | ||
267 | _popupmenu_help=new QPopupMenu; | |
268 | _popupmenu_help->insertItem("Quick &Reference",_dialog_help_short,SLOT(show())); | |
269 | _popupmenu_help->insertItem("User &Manual",_dialog_help_long,SLOT(show())); | |
270 | _popupmenu_help->insertSeparator(); | |
271 | _popupmenu_help->insertItem("&About",_dialog_about,SLOT(show())); | |
272 | ||
273 | _menubar->insertItem("&Help",_popupmenu_help); | |
274 | ||
275 | _grid=new QGrid(grid_size.width(),this); | |
276 | ||
277 | _label_autocool_enable=new QLabel("",_statusbar); | |
278 | _checkbox_autocool_enable=new QCheckBox("Autocool",_statusbar); | |
279 | QToolTip::add(_checkbox_autocool_enable,"Autocooling gradually reduces the chance and magnitude of mutations with time."); | |
280 | _button_autocool_reheat=new QPushButton("Reheat",_statusbar); | |
281 | QToolTip::add(_button_autocool_reheat,"Reheat restarts the autocooling generation count, restoring the full strength of mutations."); | |
259 | menuBar()->addSeparator(); | |
260 | ||
261 | _popupmenu_help=menuBar()->addMenu("&Help"); | |
262 | _popupmenu_help->addAction("Quick Reference",_dialog_help_short,SLOT(show())); | |
263 | _popupmenu_help->addAction("User Manual",_dialog_help_long,SLOT(show())); | |
264 | _popupmenu_help->addSeparator(); | |
265 | _popupmenu_help->addAction("About",_dialog_about,SLOT(show())); | |
266 | ||
267 | _checkbox_autocool_enable=new QCheckBox("Autocool"); | |
268 | _checkbox_autocool_enable->setToolTip("Autocooling gradually reduces the chance and magnitude of mutations with time."); | |
269 | _label_autocool_enable=new QLabel(""); // Used to display generation count | |
270 | _button_autocool_reheat=new QPushButton("Reheat"); | |
271 | _button_autocool_reheat->setToolTip("Reheat restarts the autocooling generation count, restoring the full strength of mutations."); | |
282 | 272 | |
283 | 273 | connect(_checkbox_autocool_enable,SIGNAL(stateChanged(int)),_dialog_mutation_parameters,SLOT(changed_autocool_enable(int))); |
284 | 274 | connect(_button_autocool_reheat,SIGNAL(clicked()),_dialog_mutation_parameters,SLOT(reheat())); |
285 | 275 | |
286 | _statusbar->addWidget(new QHBox(_statusbar),1,true); | |
287 | _statusbar->addWidget(_checkbox_autocool_enable,0,true); | |
288 | _statusbar->addWidget(_label_autocool_enable,0,true); | |
289 | _statusbar->addWidget(_button_autocool_reheat,0,true); | |
276 | _statusbar->addPermanentWidget(_checkbox_autocool_enable); | |
277 | _statusbar->addPermanentWidget(_label_autocool_enable); | |
278 | _statusbar->addPermanentWidget(_button_autocool_reheat); | |
290 | 279 | |
291 | 280 | connect( |
292 | 281 | &_render_parameters,SIGNAL(changed()), |
298 | 287 | this,SLOT(mutation_parameters_changed()) |
299 | 288 | ); |
300 | 289 | |
301 | // We need to make sure the display grid gets all the space it can | |
290 | ||
291 | _farm[0]=std::auto_ptr<MutatableImageComputerFarm>(new MutatableImageComputerFarm(n_threads,niceness_grid)); | |
292 | if (separate_farm_for_enlargements) | |
293 | { | |
294 | _farm[1]=std::auto_ptr<MutatableImageComputerFarm>(new MutatableImageComputerFarm(n_threads,niceness_enlargements)); | |
295 | } | |
296 | ||
297 | _grid=new QWidget; | |
298 | QGridLayout*const grid_layout=new QGridLayout; | |
299 | _grid->setLayout(grid_layout); | |
302 | 300 | setCentralWidget(_grid); |
303 | 301 | |
302 | //! \todo frames and framerate should be retained and modifiable from the GUI | |
303 | for (int r=0;r<grid_size.height();r++) | |
304 | for (int c=0;c<grid_size.width();c++) | |
305 | { | |
306 | MutatableImageDisplay*const d=new MutatableImageDisplay(this,true,false,QSize(0,0),frames,framerate); | |
307 | grid_layout->addWidget(d,r,c); | |
308 | displays().push_back(d); | |
309 | } | |
310 | ||
304 | 311 | _timer=new QTimer(this); |
305 | ||
306 | 312 | connect( |
307 | 313 | _timer,SIGNAL(timeout()), |
308 | 314 | this, SLOT(tick()) |
309 | 315 | ); |
310 | ||
311 | _farm[0]=std::auto_ptr<MutatableImageComputerFarm>(new MutatableImageComputerFarm(n_threads,niceness_grid)); | |
312 | if (separate_farm_for_enlargements) | |
313 | { | |
314 | _farm[1]=std::auto_ptr<MutatableImageComputerFarm>(new MutatableImageComputerFarm(n_threads,niceness_enlargements)); | |
315 | } | |
316 | ||
317 | //! \todo frames and framerate should be retained and modifiable from the GUI | |
318 | for (int r=0;r<grid_size.height();r++) | |
319 | for (int c=0;c<grid_size.width();c++) | |
320 | { | |
321 | displays().push_back(new MutatableImageDisplay(_grid,this,true,false,QSize(0,0),frames,framerate)); | |
322 | } | |
323 | ||
324 | 316 | // Run tick() at 100Hz |
325 | 317 | _timer->start(10); |
326 | 318 | |
372 | 364 | std::clog << "...completed Evolvotron shutdown\n"; |
373 | 365 | } |
374 | 366 | |
375 | const bool EvolvotronMain::favourite_function(const std::string& f) | |
367 | bool EvolvotronMain::favourite_function(const std::string& f) | |
376 | 368 | { |
377 | 369 | return _dialog_favourite->favourite_function(f); |
378 | 370 | } |
426 | 418 | |
427 | 419 | void EvolvotronMain::set_undoable(bool v,const std::string& action_name) |
428 | 420 | { |
429 | _popupmenu_edit->changeItem(_popupmenu_edit_undo_id,QString(("&Undo "+action_name).c_str())); | |
430 | _popupmenu_edit->setItemEnabled(_popupmenu_edit_undo_id,v); | |
421 | _popupmenu_edit_undo_action->setText(QString(("Undo "+action_name).c_str())); | |
422 | _popupmenu_edit_undo_action->setEnabled(v); | |
431 | 423 | } |
432 | 424 | |
433 | 425 | void EvolvotronMain::respawn(MutatableImageDisplay* display) |
614 | 606 | showNormal(); |
615 | 607 | menuBar()->show(); |
616 | 608 | statusBar()->show(); |
617 | _popupmenu_settings->setItemChecked(_menu_item_number_fullscreen,false); | |
618 | _popupmenu_settings->setItemChecked(_menu_item_number_hide_menu,false); | |
619 | } | |
620 | else if (e->key()==Qt::Key_F && !(e->state()^Qt::ControlButton)) | |
621 | { | |
622 | //Ctrl-F toggles fullscreen mode | |
623 | toggle_fullscreen(); | |
624 | } | |
625 | else if (e->key()==Qt::Key_M && !(e->state()^Qt::ControlButton)) | |
626 | { | |
627 | //Ctrl-M toggles menu and status-bar display | |
628 | toggle_hide_menu(); | |
629 | } | |
630 | else if (e->key()==Qt::Key_R && !(e->state()^Qt::ControlButton)) | |
631 | { | |
632 | //Ctrl-R does a restart mainly because that's most useful in full-screen mode | |
633 | reset_warm(); | |
634 | } | |
635 | else if (e->key()==Qt::Key_Z && !(e->state()^Qt::ControlButton)) | |
636 | { | |
637 | //Ctrl-Z does an undo | |
638 | undo(); | |
639 | } | |
640 | else | |
641 | { | |
642 | // Perhaps it's for someone else | |
643 | e->ignore(); | |
644 | } | |
609 | _menu_action_fullscreen->setChecked(false); | |
610 | _menu_action_hide_menu->setChecked(false); | |
611 | } | |
612 | else if (e->key()==Qt::Key_Z && !(e->modifiers()^Qt::ControlModifier)) | |
613 | { | |
614 | //Ctrl-Z does an undo | |
615 | undo(); | |
616 | } | |
617 | else | |
618 | { | |
619 | // Perhaps it's for someone else | |
620 | e->ignore(); | |
621 | } | |
645 | 622 | } |
646 | 623 | |
647 | 624 | |
650 | 627 | if (isFullScreen()) |
651 | 628 | { |
652 | 629 | showNormal(); |
653 | _popupmenu_settings->setItemChecked(_menu_item_number_fullscreen,false); | |
630 | _menu_action_fullscreen->setChecked(false); | |
654 | 631 | } |
655 | 632 | else |
656 | 633 | { |
657 | 634 | showFullScreen(); |
658 | _popupmenu_settings->setItemChecked(_menu_item_number_fullscreen,true); | |
635 | _menu_action_fullscreen->setChecked(true); | |
659 | 636 | } |
660 | 637 | } |
661 | 638 | |
664 | 641 | if (menuBar()->isHidden()) |
665 | 642 | { |
666 | 643 | menuBar()->show(); |
667 | _popupmenu_settings->setItemChecked(_menu_item_number_hide_menu,false); | |
668 | } | |
669 | else if (menuBar()->isShown()) | |
644 | _menu_action_hide_menu->setChecked(false); | |
645 | } | |
646 | else if (menuBar()->isVisible()) | |
670 | 647 | { |
671 | 648 | menuBar()->hide(); |
672 | _popupmenu_settings->setItemChecked(_menu_item_number_hide_menu,true); | |
649 | _menu_action_hide_menu->setChecked(true); | |
673 | 650 | } |
674 | 651 | |
675 | 652 | if (statusBar()->isHidden()) |
676 | 653 | statusBar()->show(); |
677 | else if (statusBar()->isShown()) | |
654 | else if (statusBar()->isVisible()) | |
678 | 655 | statusBar()->hide(); |
679 | 656 | } |
680 | 657 |
21 | 21 | |
22 | 22 | #ifndef _evolvotron_main_h_ |
23 | 23 | #define _evolvotron_main_h_ |
24 | ||
25 | #include <qcheckbox.h> | |
26 | #include <qmenubar.h> | |
27 | #include <qstatusbar.h> | |
28 | #include <qmainwindow.h> | |
29 | #include <qgrid.h> | |
30 | #include <qtimer.h> | |
31 | 24 | |
32 | 25 | #include "function_registry.h" |
33 | 26 | #include "transform_factory.h" |
77 | 70 | protected: |
78 | 71 | |
79 | 72 | //! Class encapsulating everything needed for undo functionality. |
73 | /*! \todo This is too big to be a nested class. | |
74 | */ | |
80 | 75 | class History |
81 | 76 | { |
82 | 77 | protected: |
181 | 176 | //! Dialog for selecting a favourite function (also holds the state for favourite stuff) |
182 | 177 | DialogFavourite* _dialog_favourite; |
183 | 178 | |
184 | //! The menubar. | |
185 | QMenuBar* _menubar; | |
186 | ||
187 | 179 | //! The file menu. |
188 | QPopupMenu* _popupmenu_file; | |
180 | QMenu* _popupmenu_file; | |
189 | 181 | |
190 | 182 | //! The edit menu. |
191 | QPopupMenu* _popupmenu_edit; | |
183 | QMenu* _popupmenu_edit; | |
192 | 184 | |
193 | 185 | //! ID for the undo item (so we can disable it). |
194 | int _popupmenu_edit_undo_id; | |
186 | QAction* _popupmenu_edit_undo_action; | |
195 | 187 | |
196 | 188 | //! The settings menu |
197 | QPopupMenu* _popupmenu_settings; | |
198 | ||
199 | //! Item number for setting check mark | |
200 | int _menu_item_number_fullscreen; | |
201 | ||
202 | //! Item number for setting check mark | |
203 | int _menu_item_number_hide_menu; | |
189 | QMenu* _popupmenu_settings; | |
190 | ||
191 | //! Action for setting fullscreen | |
192 | QAction* _menu_action_fullscreen; | |
193 | ||
194 | //! Action for hiding menubar | |
195 | QAction* _menu_action_hide_menu; | |
204 | 196 | |
205 | 197 | //! The help menu. |
206 | QPopupMenu* _popupmenu_help; | |
198 | QMenu* _popupmenu_help; | |
207 | 199 | |
208 | 200 | //! Select autocooling (also serves to reset the generation count). |
209 | 201 | QCheckBox* _checkbox_autocool_enable; |
215 | 207 | QPushButton* _button_autocool_reheat; |
216 | 208 | |
217 | 209 | //! Grid for image display areas |
218 | QGrid* _grid; | |
210 | QWidget* _grid; | |
219 | 211 | |
220 | 212 | //! Timer to drive tick() slot |
221 | 213 | QTimer* _timer; |
250 | 242 | } |
251 | 243 | |
252 | 244 | //! Accessor. |
253 | const SpawnMemberFn last_spawn_method() const | |
245 | SpawnMemberFn last_spawn_method() const | |
254 | 246 | { |
255 | 247 | return _last_spawn_method; |
256 | 248 | } |
307 | 299 | ~EvolvotronMain(); |
308 | 300 | |
309 | 301 | //! Accessor. Returns true if function name recognised. Forwards to DialogFavourite. |
310 | const bool favourite_function(const std::string& f); | |
302 | bool favourite_function(const std::string& f); | |
311 | 303 | |
312 | 304 | //! Accessor. Forwards to DialogFavourite. |
313 | 305 | void favourite_function_unwrapped(bool v); |
27 | 27 | mutatable_image_display.h \ |
28 | 28 | mutatable_image_display_big.h \ |
29 | 29 | mutation_parameters_qobject.h \ |
30 | platform_specific.h \ | |
30 | 31 | render_parameters.h \ |
31 | 32 | transform_factory.h \ |
32 | usage_text.h \ | |
33 | vbox_scrollview.h | |
33 | usage_text.h | |
34 | 34 | |
35 | 35 | SOURCES += \ |
36 | 36 | args.cpp \ |
50 | 50 | mutatable_image_display.cpp \ |
51 | 51 | mutatable_image_display_big.cpp \ |
52 | 52 | mutation_parameters_qobject.cpp \ |
53 | platform_specific.cpp \ | |
53 | 54 | render_parameters.cpp \ |
54 | transform_factory.cpp \ | |
55 | vbox_scrollview.cpp | |
55 | transform_factory.cpp | |
56 | 56 |
25 | 25 | |
26 | 26 | #include "libfunction_precompiled.h" |
27 | 27 | |
28 | #include <qapplication.h> | |
29 | #include <qcheckbox.h> | |
30 | #include <qcombobox.h> | |
31 | #include <qcursor.h> | |
32 | #include <qdatetime.h> | |
33 | #include <qdialog.h> | |
34 | #include <qgrid.h> | |
35 | #include <qgroupbox.h> | |
36 | #include <qhbox.h> | |
37 | #include <qhgroupbox.h> | |
38 | #include <qimage.h> | |
39 | #include <qlabel.h> | |
40 | #include <qlayout.h> | |
41 | #include <qmainwindow.h> | |
42 | #include <qmessagebox.h> | |
43 | #include <qobject.h> | |
44 | #include <qpushbutton.h> | |
45 | #include <qradiobutton.h> | |
46 | #include <qregexp.h> | |
47 | #include <qslider.h> | |
48 | #include <qspinbox.h> | |
49 | #include <qstatusbar.h> | |
50 | #include <qstring.h> | |
51 | #include <qtabwidget.h> | |
52 | #include <qtextedit.h> | |
53 | #include <qtooltip.h> | |
54 | #include <qvbox.h> | |
55 | #include <qvbuttongroup.h> | |
56 | #include <qvgroupbox.h> | |
57 | #include <qwidget.h> | |
28 | #include <stack> | |
29 | ||
30 | #include <boost/optional.hpp> | |
31 | ||
32 | #include <QtXml> | |
33 | ||
34 | #include <QApplication> | |
35 | #include <QButtonGroup> | |
36 | #include <QCheckBox> | |
37 | #include <QComboBox> | |
38 | #include <QCursor> | |
39 | #include <QDateTime> | |
40 | #include <QDialog> | |
41 | #include <QFileDialog> | |
42 | #include <QGroupBox> | |
43 | #include <QImage> | |
44 | #include <QKeyEvent> | |
45 | #include <QLabel> | |
46 | #include <QList> | |
47 | #include <QLayout> | |
48 | #include <QMainWindow> | |
49 | #include <QMenuBar> | |
50 | #include <QMessageBox> | |
51 | #include <QMutex> | |
52 | #include <QObject> | |
53 | #include <QPixmap> | |
54 | #include <QPainter> | |
55 | #include <QPushButton> | |
56 | #include <QRadioButton> | |
57 | #include <QRegExp> | |
58 | #include <QScrollArea> | |
59 | #include <QSize> | |
60 | #include <QSlider> | |
61 | #include <QSpinBox> | |
62 | #include <QStatusBar> | |
63 | #include <QString> | |
64 | #include <QTabWidget> | |
65 | #include <QTextBrowser> | |
66 | #include <QTextEdit> | |
67 | #include <QThread> | |
68 | #include <QTimer> | |
69 | #include <QToolTip> | |
70 | #include <QWaitCondition> | |
71 | #include <QWidget> | |
72 | ||
73 | #define stringify(S) __STRING(S) | |
58 | 74 | |
59 | 75 | #endif |
22 | 22 | #include "libevolvotron_precompiled.h" |
23 | 23 | |
24 | 24 | #include "mutatable_image.h" |
25 | ||
26 | #include <stack> | |
27 | ||
28 | #include <qxml.h> | |
29 | 25 | |
30 | 26 | #include "function_node_info.h" |
31 | 27 | #include "function_top.h" |
87 | 83 | return boost::shared_ptr<const MutatableImage>(new MutatableImage(root,sinusoidal_z(),spheremap(),lock)); |
88 | 84 | } |
89 | 85 | |
90 | const bool MutatableImage::is_constant() const | |
86 | bool MutatableImage::is_constant() const | |
91 | 87 | { |
92 | 88 | return top().is_constant(); |
93 | 89 | } |
94 | 90 | |
95 | const bool MutatableImage::ok() const | |
91 | bool MutatableImage::ok() const | |
96 | 92 | { |
97 | 93 | return top().ok(); |
98 | 94 | } |
205 | 201 | { |
206 | 202 | out |
207 | 203 | << "<?xml version=\"1.0\"?>\n" |
208 | << "<evolvotron-image-function version=\"" | |
209 | << EVOLVOTRON_VERSION | |
204 | << "<evolvotron-image-function version=" | |
205 | << "\"" | |
206 | << stringify(EVOLVOTRON_VERSION) | |
210 | 207 | << "\"" |
211 | 208 | << " zsweep=\"" |
212 | 209 | << (_sinusoidal_z ? "sinusoidal" : "linear") |
283 | 280 | |
284 | 281 | //! Called for start elements. |
285 | 282 | /*! Don't know anything about namespaces - parameters ignored. |
286 | Stick with latin1() conversion because we shouldn't have put anything fancy in the file | |
287 | 283 | */ |
288 | 284 | bool startElement(const QString&,const QString& localName,const QString&,const QXmlAttributes& atts) |
289 | 285 | { |
290 | const std::string element(localName.latin1()); | |
286 | const std::string element(localName.toLocal8Bit().data()); | |
291 | 287 | |
292 | 288 | if (_expect_characters) |
293 | 289 | { |
309 | 305 | else |
310 | 306 | { |
311 | 307 | const QString version=atts.value(idx); |
312 | if (version!=QString(EVOLVOTRON_VERSION)) | |
308 | if (version!=QString(stringify(EVOLVOTRON_VERSION))) | |
313 | 309 | { |
314 | 310 | QString tmp; |
315 | tmp="Warning: File saved from a different evolvotron version: "+version+"\n(This is version "+QString(EVOLVOTRON_VERSION)+")\n"; | |
316 | _report+=tmp.latin1(); | |
311 | tmp="Warning: File saved from a different evolvotron version: "+version+"\n(This is version "+QString(stringify(EVOLVOTRON_VERSION))+")\n"; | |
312 | _report+=tmp.toLocal8Bit().data(); | |
317 | 313 | } |
318 | 314 | } |
319 | 315 | |
333 | 329 | { |
334 | 330 | QString tmp; |
335 | 331 | tmp="Error: zsweep attribute expected \"sinusoidal\" or \"linear\", but got \""+zsweep+"\"\n"; |
336 | _report+=tmp.latin1(); | |
332 | _report+=tmp.toLocal8Bit().data(); | |
337 | 333 | return false; |
338 | 334 | } |
339 | 335 | } |
354 | 350 | { |
355 | 351 | QString tmp; |
356 | 352 | tmp="Error: projection attribute expected \"spheremap\" or \"planar\", but got \""+projection+"\"\n"; |
357 | _report+=tmp.latin1(); | |
353 | _report+=tmp.toLocal8Bit().data(); | |
358 | 354 | return false; |
359 | 355 | } |
360 | 356 | } |
418 | 414 | |
419 | 415 | //! We don't need to check this matches startElement |
420 | 416 | /*! Don't know anything about namespaces - parameter ignored. |
421 | Stick with latin1() conversion because we shouldn't have put anything fancy in the file | |
422 | 417 | */ |
423 | 418 | bool endElement(const QString&, const QString& localName, const QString&) |
424 | 419 | { |
425 | const std::string element(localName.latin1()); | |
420 | const std::string element(localName.toLocal8Bit().data()); | |
426 | 421 | |
427 | 422 | if (_expect_characters) |
428 | 423 | { |
440 | 435 | |
441 | 436 | bool characters(const QString& s) |
442 | 437 | { |
443 | QString stripped=s.stripWhiteSpace(); | |
438 | QString stripped=s.simplified(); | |
444 | 439 | |
445 | 440 | if (stripped.isEmpty()) |
446 | 441 | { |
451 | 446 | { |
452 | 447 | if (!_expect_characters) |
453 | 448 | { |
454 | QString tmp; | |
455 | tmp = "Error: Unexpected character data : \""+s+"\"\n"; | |
456 | _report += tmp.latin1(); | |
449 | QString tmp; | |
450 | tmp = "Error: Unexpected character data : \""+s+"\"\n"; | |
451 | _report += tmp.toLocal8Bit().data(); | |
457 | 452 | return false; |
458 | 453 | } |
459 | 454 | } |
462 | 457 | |
463 | 458 | if (_expect_characters_type) |
464 | 459 | { |
465 | _stack.top()->type(s.latin1()); | |
460 | _stack.top()->type(s.toLocal8Bit().data()); | |
466 | 461 | _expect_characters_type=false; |
467 | 462 | } |
468 | 463 | else if (_expect_characters_iterations) |
472 | 467 | _expect_characters_iterations=false; |
473 | 468 | if (!ok) |
474 | 469 | { |
475 | QString tmp; | |
476 | tmp = "Error: Couldn't parse \""+s+"\" as an integer\n"; | |
477 | _report += tmp.latin1(); | |
470 | QString tmp; | |
471 | tmp = "Error: Couldn't parse \""+s+"\" as an integer\n"; | |
472 | _report += tmp.toLocal8Bit().data(); | |
478 | 473 | return false; |
479 | } | |
474 | } | |
480 | 475 | } |
481 | 476 | else if (_expect_characters_parameter) |
482 | 477 | { |
485 | 480 | _expect_characters_parameter=false; |
486 | 481 | if (!ok) |
487 | 482 | { |
488 | QString tmp; | |
489 | tmp = "Error: Couldn't parse \""+s+"\" as a real\n"; | |
490 | _report+=tmp.latin1(); | |
483 | QString tmp; | |
484 | tmp = "Error: Couldn't parse \""+s+"\" as a real\n"; | |
485 | _report+=tmp.toLocal8Bit().data(); | |
491 | 486 | return false; |
492 | 487 | } |
493 | 488 | |
533 | 528 | if (ok) |
534 | 529 | { |
535 | 530 | // Might be a warning message in there. |
536 | report=load_handler.errorString().latin1(); | |
531 | report=load_handler.errorString().toLocal8Bit().data(); | |
537 | 532 | |
538 | 533 | assert(info.get()); |
539 | 534 | std::auto_ptr<FunctionNode> root(FunctionNode::create(function_registry,*info,report)); |
569 | 564 | { |
570 | 565 | QString tmp; |
571 | 566 | tmp = "Parse error: "+load_handler.errorString()+"\n"; |
572 | report=tmp.latin1(); | |
567 | report=tmp.toLocal8Bit().data(); | |
573 | 568 | return boost::shared_ptr<const MutatableImage>(); |
574 | 569 | } |
575 | 570 | } |
79 | 79 | const FunctionTop& top() const; |
80 | 80 | |
81 | 81 | //! Accessor. |
82 | const bool sinusoidal_z() const | |
82 | bool sinusoidal_z() const | |
83 | 83 | { |
84 | 84 | return _sinusoidal_z; |
85 | 85 | } |
86 | 86 | |
87 | 87 | //! Accessor. |
88 | const bool spheremap() const | |
88 | bool spheremap() const | |
89 | 89 | { |
90 | 90 | return _spheremap; |
91 | 91 | } |
92 | 92 | |
93 | 93 | //! Accessor. |
94 | const bool locked() const | |
94 | bool locked() const | |
95 | 95 | { |
96 | 96 | return _locked; |
97 | 97 | } |
103 | 103 | } |
104 | 104 | |
105 | 105 | //! Accessor. |
106 | const unsigned long long serial() const | |
106 | unsigned long long serial() const | |
107 | 107 | { |
108 | 108 | return _serial; |
109 | 109 | } |
127 | 127 | const XYZ get_rgb(uint x,uint y,uint f,uint width,uint height,uint frames,Random01* r01,uint multisample) const; |
128 | 128 | |
129 | 129 | //! Return whether image value is independent of position. |
130 | const bool is_constant() const; | |
130 | bool is_constant() const; | |
131 | 131 | |
132 | 132 | //! Save the function-tree to the stream |
133 | 133 | std::ostream& save_function(std::ostream& out) const; |
139 | 139 | void get_stats(uint& total_nodes,uint& total_parameters,uint& depth,uint& width,real& proportion_constant) const; |
140 | 140 | |
141 | 141 | //! Check the function tree is ok. |
142 | const bool ok() const; | |
142 | bool ok() const; | |
143 | 143 | }; |
144 | 144 | |
145 | 145 | #endif |
23 | 23 | |
24 | 24 | #include "mutatable_image_computer.h" |
25 | 25 | |
26 | // Needed for getpriority/setprioirty | |
27 | #include <sys/resource.h> | |
28 | ||
29 | 26 | #include "mutatable_image.h" |
30 | 27 | #include "mutatable_image_computer_farm.h" |
31 | 28 | #include "mutatable_image_computer_task.h" |
29 | ||
30 | #include "platform_specific.h" | |
32 | 31 | |
33 | 32 | MutatableImageComputer::MutatableImageComputer(MutatableImageComputerFarm* frm,int niceness) |
34 | 33 | : |
54 | 53 | std::clog << "...deleted a computer\n"; |
55 | 54 | } |
56 | 55 | |
57 | /*! Compute threads run this method untill killed (probably by the destructor being invoked by the original spawning thread. | |
56 | /*! Compute threads run this method until killed (probably by the destructor being invoked by the original spawning thread. | |
58 | 57 | */ |
59 | 58 | void MutatableImageComputer::run() |
60 | 59 | { |
61 | 60 | std::clog << "Thread starting\n"; |
62 | 61 | |
63 | // Lower compute thread priority slightly; | |
64 | // computing yet more stuff is less important than displaying the results we've got. | |
65 | /*! \todo: People porting to non-Linux (BSD, MacOS, Fink etc) please send | |
66 | a suitable #ifdef-able patch if you need something different here. | |
67 | Note that this code relies on Linux NPTL's non-Posix-compliant | |
68 | thread-specific nice value (although without a suitable replacement | |
69 | per-thread priority mechanism it's just as well it's that way). | |
70 | \todo: Should check some error codes, but it's pretty harmless if it doesn't work. | |
71 | */ | |
72 | const int current_priority=getpriority(PRIO_PROCESS,0); | |
73 | setpriority(PRIO_PROCESS,0,std::min(19,current_priority+_niceness)); | |
62 | // Lower compute thread priority slightly; computing yet more stuff | |
63 | // is less important than displaying the results we've got so far. | |
64 | add_thread_niceness(_niceness); | |
74 | 65 | |
75 | 66 | // Run until something sets the kill flag |
76 | 67 | while(!communications().kill()) |
21 | 21 | |
22 | 22 | #ifndef _mutatable_image_computer_h_ |
23 | 23 | #define _mutatable_image_computer_h_ |
24 | ||
25 | #include <qthread.h> | |
26 | #include <qmutex.h> | |
27 | 24 | |
28 | 25 | #include "mutatable_image.h" |
29 | 26 | #include "random.h" |
83 | 80 | /*! Mutex is recursive to allow nesting. |
84 | 81 | */ |
85 | 82 | Communications() |
86 | :_mutex(true) | |
83 | :_mutex() | |
87 | 84 | ,_defer(false) |
88 | 85 | ,_abort(false) |
89 | 86 | ,_kill(false) |
96 | 93 | _defer=v; |
97 | 94 | } |
98 | 95 | //! Mutex-protected accessor. |
99 | const bool defer() const | |
96 | bool defer() const | |
100 | 97 | { |
101 | 98 | QMutexLocker lock(&_mutex); |
102 | 99 | const bool ret=_defer; |
109 | 106 | _abort=v; |
110 | 107 | } |
111 | 108 | //! Mutex-protected accessor. |
112 | const bool abort() const | |
109 | bool abort() const | |
113 | 110 | { |
114 | 111 | QMutexLocker lock(&_mutex); |
115 | 112 | const bool ret=_abort; |
122 | 119 | _kill=v; |
123 | 120 | } |
124 | 121 | //! Mutex-protected accessor. |
125 | const bool kill() const | |
122 | bool kill() const | |
126 | 123 | { |
127 | 124 | QMutexLocker lock(&_mutex); |
128 | 125 | const bool ret=_kill; |
129 | 126 | return ret; |
130 | 127 | } |
131 | 128 | //! Check union of all flags with only one mutex lock. |
132 | const bool kill_or_abort_or_defer() const | |
129 | bool kill_or_abort_or_defer() const | |
133 | 130 | { |
134 | 131 | QMutexLocker lock(&_mutex); |
135 | 132 | const bool ret=(_kill || _abort || _defer); |
161 | 158 | } |
162 | 159 | |
163 | 160 | //! Accessor. |
164 | MutatableImageComputerFarm*const farm() const | |
161 | MutatableImageComputerFarm* farm() const | |
165 | 162 | { |
166 | 163 | return _farm; |
167 | 164 | } |
61 | 61 | } |
62 | 62 | |
63 | 63 | //! Predicate function to test whether a task has been aborted |
64 | static const bool predicate_aborted(const boost::shared_ptr<const MutatableImageComputerTask> t) | |
64 | static bool predicate_aborted(const boost::shared_ptr<const MutatableImageComputerTask> t) | |
65 | 65 | { |
66 | 66 | return t->aborted(); |
67 | 67 | } |
236 | 236 | } |
237 | 237 | } |
238 | 238 | |
239 | const uint MutatableImageComputerFarm::tasks() const | |
239 | uint MutatableImageComputerFarm::tasks() const | |
240 | 240 | { |
241 | 241 | uint ret=0; |
242 | 242 |
21 | 21 | |
22 | 22 | #ifndef _mutatable_image_computer_farm_h_ |
23 | 23 | #define _mutatable_image_computer_farm_h_ |
24 | ||
25 | #include <qthread.h> | |
26 | 24 | |
27 | 25 | #include "useful.h" |
28 | 26 | |
106 | 104 | ~MutatableImageComputerFarm(); |
107 | 105 | |
108 | 106 | //! Accessor. |
109 | const uint num_threads() const | |
107 | uint num_threads() const | |
110 | 108 | { |
111 | 109 | return _computers.size(); |
112 | 110 | } |
133 | 131 | void abort_for(const MutatableImageDisplay* disp); |
134 | 132 | |
135 | 133 | //! Number of tasks in queues |
136 | const uint tasks() const; | |
134 | uint tasks() const; | |
137 | 135 | }; |
138 | 136 | |
139 | 137 | #endif |
83 | 83 | { |
84 | 84 | for (uint f=0;f<frames();f++) |
85 | 85 | { |
86 | _images.push_back(QImage(fragment_size(),32)); | |
86 | _images.push_back(QImage(fragment_size(),QImage::Format_RGB32)); | |
87 | 87 | } |
88 | 88 | } |
89 | 89 |
21 | 21 | |
22 | 22 | #ifndef _mutatable_image_computer_task_h_ |
23 | 23 | #define _mutatable_image_computer_task_h_ |
24 | ||
25 | #include <qsize.h> | |
26 | 24 | |
27 | 25 | #include "mutatable_image.h" |
28 | 26 | #include "mutatable_image_display.h" |
144 | 142 | } |
145 | 143 | |
146 | 144 | //! Accessor. |
147 | MutatableImageDisplay*const display() const | |
145 | MutatableImageDisplay* display() const | |
148 | 146 | { |
149 | 147 | return _display; |
150 | 148 | } |
174 | 172 | } |
175 | 173 | |
176 | 174 | //! Accessor. |
177 | const uint frames() const | |
175 | uint frames() const | |
178 | 176 | { |
179 | 177 | return _frames; |
180 | 178 | } |
181 | 179 | |
182 | 180 | //! Accessor. |
183 | const uint level() const | |
181 | uint level() const | |
184 | 182 | { |
185 | 183 | return _level; |
186 | 184 | } |
187 | 185 | |
188 | 186 | //! Accessor. |
189 | const uint fragment() const | |
187 | uint fragment() const | |
190 | 188 | { |
191 | 189 | return _fragment; |
192 | 190 | } |
193 | 191 | |
194 | 192 | //! Accessor. |
195 | const uint number_of_fragments() const | |
193 | uint number_of_fragments() const | |
196 | 194 | { |
197 | 195 | return _number_of_fragments; |
198 | 196 | } |
199 | 197 | |
200 | 198 | //! Accessor. |
201 | const bool jittered_samples() const | |
199 | bool jittered_samples() const | |
202 | 200 | { |
203 | 201 | return _jittered_samples; |
204 | 202 | } |
205 | 203 | |
206 | 204 | //! Accessor. |
207 | const uint multisample_grid() const | |
205 | uint multisample_grid() const | |
208 | 206 | { |
209 | 207 | return _multisample_grid; |
210 | 208 | } |
211 | 209 | |
212 | 210 | //! Serial number |
213 | const unsigned long long int serial() const | |
211 | unsigned long long int serial() const | |
214 | 212 | { |
215 | 213 | return _serial; |
216 | 214 | } |
217 | 215 | |
218 | 216 | //! Accessor. |
219 | const uint priority() const | |
217 | uint priority() const | |
220 | 218 | { |
221 | 219 | return _priority; |
222 | 220 | } |
236 | 234 | } |
237 | 235 | |
238 | 236 | //! Accessor. |
239 | const uint current_col() const | |
237 | uint current_col() const | |
240 | 238 | { |
241 | 239 | return _current_col; |
242 | 240 | } |
243 | 241 | |
244 | 242 | //! Accessor. |
245 | const uint current_row() const | |
243 | uint current_row() const | |
246 | 244 | { |
247 | 245 | return _current_row; |
248 | 246 | } |
249 | 247 | |
250 | 248 | //! Accessor. |
251 | const uint current_frame() const | |
249 | uint current_frame() const | |
252 | 250 | { |
253 | 251 | return _current_frame; |
254 | 252 | } |
255 | 253 | |
256 | 254 | //! Accessor. |
257 | const uint current_pixel() const | |
255 | uint current_pixel() const | |
258 | 256 | { |
259 | 257 | return _current_pixel; |
260 | 258 | } |
261 | 259 | |
262 | 260 | //!Accessor. |
263 | const bool completed() const | |
261 | bool completed() const | |
264 | 262 | { |
265 | 263 | return _completed; |
266 | 264 | } |
23 | 23 | #include "libevolvotron_precompiled.h" |
24 | 24 | |
25 | 25 | #include "mutatable_image_display.h" |
26 | ||
27 | #include <qscrollview.h> | |
28 | #include <qmessagebox.h> | |
29 | #include <qfiledialog.h> | |
30 | #include <qpngio.h> | |
31 | 26 | |
32 | 27 | #include "mutatable_image_display_big.h" |
33 | 28 | #include "evolvotron_main.h" |
44 | 39 | - and the size of the offscreen buffer (only used if fixed_size is true). |
45 | 40 | Note that we use Qt's WDestructiveCode flag to ensure the destructor is called on close |
46 | 41 | */ |
47 | MutatableImageDisplay::MutatableImageDisplay(QWidget* parent,EvolvotronMain* mn,bool full,bool fixed_size,const QSize& sz,uint f,uint fr) | |
48 | :QWidget(parent,0,Qt::WDestructiveClose) | |
49 | ,_main(mn) | |
50 | ,_full_functionality(full) | |
51 | ,_fixed_size(fixed_size) | |
52 | ,_image_size(sz) | |
53 | ,_frames(f) | |
54 | ,_framerate(fr) | |
55 | ,_current_frame(0) | |
56 | ,_animate_reverse(false) | |
57 | ,_timer(0) | |
58 | ,_resize_in_progress(false) | |
59 | ,_current_display_level(0) | |
60 | ,_current_display_multisample_grid(0) | |
61 | ,_icon_serial(0LL) | |
62 | ,_properties(0) | |
63 | ,_menu(0) | |
64 | ,_menu_big(0) | |
65 | ,_serial(0LL) | |
66 | { | |
67 | setWFlags(getWFlags()|Qt::WNoAutoErase); | |
68 | setBackgroundMode(Qt::NoBackground); | |
42 | MutatableImageDisplay::MutatableImageDisplay(EvolvotronMain* mn,bool full_functionality,bool fixed_size,const QSize& sz,uint f,uint fr) | |
43 | :_main(mn) | |
44 | ,_full_functionality(full_functionality) | |
45 | ,_fixed_size(fixed_size) | |
46 | ,_image_size(sz) | |
47 | ,_frames(f) | |
48 | ,_framerate(fr) | |
49 | ,_current_frame(0) | |
50 | ,_animate_reverse(false) | |
51 | ,_timer(0) | |
52 | ,_resize_in_progress(false) | |
53 | ,_current_display_level(0) | |
54 | ,_current_display_multisample_grid(0) | |
55 | ,_icon_serial(0LL) | |
56 | ,_properties(0) | |
57 | ,_menu(0) | |
58 | ,_menu_big(0) | |
59 | ,_menu_item_action_lock(0) | |
60 | ,_serial(0LL) | |
61 | { | |
62 | setAttribute(Qt::WA_DeleteOnClose,true); | |
63 | ||
64 | setFocusPolicy(Qt::StrongFocus); | |
69 | 65 | |
70 | 66 | _properties=new DialogMutatableImageDisplay(this); |
71 | 67 | |
72 | _menu=new QPopupMenu(this); | |
68 | _menu=new QMenu(this); | |
73 | 69 | |
74 | 70 | // Most items on the context menu aren't appropriate for a window displaying a single big image |
75 | 71 | if (_full_functionality) |
76 | 72 | { |
77 | // We want to use a checkmark for "Locked" | |
78 | _menu->setCheckable(true); | |
79 | ||
80 | _menu->insertItem("&Respawn",this,SLOT(menupick_respawn())); | |
81 | ||
82 | _menu->insertSeparator(); | |
83 | ||
84 | _menu->insertItem("&Spawn",this,SLOT(menupick_spawn())); | |
85 | _menu->insertItem("Spawn re&coloured",this,SLOT(menupick_spawn_recoloured())); | |
86 | ||
87 | _menu_warped=new QPopupMenu(this); | |
88 | _menu_warped->insertItem("Random &Mix",this,SLOT(menupick_spawn_warped_random())); | |
89 | _menu_warped->insertItem("Zoom &In",this,SLOT(menupick_spawn_warped_zoom_in())); | |
90 | _menu_warped->insertItem("Zoom &Out",this,SLOT(menupick_spawn_warped_zoom_out())); | |
91 | _menu_warped->insertItem("&Rotate",this,SLOT(menupick_spawn_warped_rotate())); | |
92 | _menu_warped->insertItem("&Pan XY",this,SLOT(menupick_spawn_warped_pan_xy())); | |
93 | _menu_warped->insertItem("Pan &X",this,SLOT(menupick_spawn_warped_pan_x())); | |
94 | _menu_warped->insertItem("Pan &Y",this,SLOT(menupick_spawn_warped_pan_y())); | |
95 | _menu_warped->insertItem("Pan &Z",this,SLOT(menupick_spawn_warped_pan_z())); | |
96 | ||
97 | _menu->insertItem("Spawn &warped",_menu_warped); | |
98 | ||
99 | _menu->insertSeparator(); | |
100 | ||
101 | _menu_item_number_lock =_menu->insertItem("&Lock",this,SLOT(menupick_lock())); | |
102 | ||
103 | _menu->insertSeparator(); | |
73 | _menu->addAction("Respawn",this,SLOT(menupick_respawn())); | |
74 | ||
75 | _menu->addSeparator(); | |
76 | ||
77 | _menu->addAction("Spawn",this,SLOT(menupick_spawn())); | |
78 | _menu->addAction("Spawn recoloured",this,SLOT(menupick_spawn_recoloured())); | |
79 | ||
80 | _menu_warped=_menu->addMenu("Spawn warped"); | |
81 | _menu_warped->addAction("Random Mix",this,SLOT(menupick_spawn_warped_random()) ); | |
82 | _menu_warped->addAction("Zoom In" ,this,SLOT(menupick_spawn_warped_zoom_in()) ); | |
83 | _menu_warped->addAction("Zoom Out" ,this,SLOT(menupick_spawn_warped_zoom_out())); | |
84 | _menu_warped->addAction("Rotate" ,this,SLOT(menupick_spawn_warped_rotate()) ); | |
85 | _menu_warped->addAction("Pan XY" ,this,SLOT(menupick_spawn_warped_pan_xy()) ); | |
86 | _menu_warped->addAction("Pan X" ,this,SLOT(menupick_spawn_warped_pan_x()) ); | |
87 | _menu_warped->addAction("Pan Y" ,this,SLOT(menupick_spawn_warped_pan_y()) ); | |
88 | _menu_warped->addAction("Pan Z" ,this,SLOT(menupick_spawn_warped_pan_z()) ); | |
89 | ||
90 | _menu->addSeparator(); | |
91 | ||
92 | _menu_item_action_lock=_menu->addAction("Lock",this,SLOT(menupick_lock())); | |
93 | _menu_item_action_lock->setCheckable(true); | |
94 | ||
95 | _menu->addSeparator(); | |
104 | 96 | } |
105 | 97 | |
106 | _menu_big=new QPopupMenu(this); | |
107 | _menu_big->insertItem("&Resizable",this,SLOT(menupick_big_resizable())); | |
108 | _menu_big->insertSeparator(); | |
109 | _menu_big->insertItem("&256x256",this,SLOT(menupick_big_256x256())); | |
110 | _menu_big->insertItem("&512x512",this,SLOT(menupick_big_512x512())); | |
111 | _menu_big->insertItem("&768x768",this,SLOT(menupick_big_768x768())); | |
112 | _menu_big->insertItem("&1024x1024",this,SLOT(menupick_big_1024x1024())); | |
113 | _menu_big->insertItem("&2048x2048",this,SLOT(menupick_big_2048x2048())); | |
114 | _menu_big->insertItem("&4096x4096",this,SLOT(menupick_big_4096x4096())); | |
115 | _menu_big->insertSeparator(); | |
116 | _menu_big->insertItem("640x&480",this,SLOT(menupick_big_640x480())); | |
117 | _menu_big->insertItem("1024x&768",this,SLOT(menupick_big_1024x768())); | |
118 | _menu_big->insertItem("1280x&960",this,SLOT(menupick_big_1280x960())); | |
119 | _menu_big->insertItem("1&600x1200",this,SLOT(menupick_big_1600x1200())); | |
120 | ||
121 | _menu->insertItem("&Enlarge",_menu_big); | |
122 | ||
123 | _menu->insertSeparator(); | |
98 | _menu_big=_menu->addMenu("Enlarge"); | |
99 | _menu_big->addAction("Resizable",this,SLOT(menupick_big_resizable())); | |
100 | _menu_big->addSeparator(); | |
101 | _menu_big->addAction("256x256" ,this,SLOT(menupick_big_256x256())); | |
102 | _menu_big->addAction("512x512" ,this,SLOT(menupick_big_512x512()) ); | |
103 | _menu_big->addAction("768x768" ,this,SLOT(menupick_big_768x768()) ); | |
104 | _menu_big->addAction("1024x1024",this,SLOT(menupick_big_1024x1024())); | |
105 | _menu_big->addAction("2048x2048",this,SLOT(menupick_big_2048x2048())); | |
106 | _menu_big->addAction("4096x4096",this,SLOT(menupick_big_4096x4096())); | |
107 | _menu_big->addSeparator(); | |
108 | _menu_big->addAction("640x480" ,this,SLOT(menupick_big_640x480()) ); | |
109 | _menu_big->addAction("1024x768" ,this,SLOT(menupick_big_1024x768()) ); | |
110 | _menu_big->addAction("1280x960" ,this,SLOT(menupick_big_1280x960()) ); | |
111 | _menu_big->addAction("1600x1200",this,SLOT(menupick_big_1600x1200())); | |
112 | ||
113 | _menu->addSeparator(); | |
124 | 114 | |
125 | _menu->insertItem("Save &image",this,SLOT(menupick_save_image())); | |
126 | _menu->insertItem("Save &function",this,SLOT(menupick_save_function())); | |
115 | _menu->addAction("Save image",this,SLOT(menupick_save_image())); | |
116 | _menu->addAction("Save function",this,SLOT(menupick_save_function())); | |
127 | 117 | |
128 | 118 | if (_full_functionality) |
129 | 119 | { |
130 | _menu->insertItem("L&oad function",this,SLOT(menupick_load_function())); | |
131 | } | |
132 | ||
133 | _menu->insertSeparator(); | |
134 | _menu->insertItem("Simplif&y function",this,SLOT(menupick_simplify())); | |
135 | _menu->insertItem("&Properties...",this,SLOT(menupick_properties())); | |
120 | _menu->addAction("Load function",this,SLOT(menupick_load_function())); | |
121 | } | |
122 | ||
123 | _menu->addSeparator(); | |
124 | _menu->addAction("Simplify function",this,SLOT(menupick_simplify())); | |
125 | _menu->addAction("Properties...",this,SLOT(menupick_properties())); | |
136 | 126 | |
137 | 127 | main().hello(this); |
138 | 128 | |
175 | 165 | _offscreen_images.clear(); |
176 | 166 | } |
177 | 167 | |
178 | const uint MutatableImageDisplay::simplify_constants(bool single_action) | |
168 | uint MutatableImageDisplay::simplify_constants(bool single_action) | |
179 | 169 | { |
180 | 170 | if (single_action) main().history().begin_action("simplify"); |
181 | 171 | |
203 | 193 | |
204 | 194 | if (single_action) |
205 | 195 | { |
206 | if (_icon.get()) _main->setIcon(*_icon); | |
196 | if (_icon.get()) _main->setWindowIcon(*_icon); | |
207 | 197 | |
208 | 198 | std::stringstream msg; |
209 | 199 | msg << "Eliminated " << nodes_eliminated << " redundant function nodes\n"; |
233 | 223 | _animate_reverse=true; |
234 | 224 | } |
235 | 225 | } |
236 | repaint(false); // Use repaint rather than update because we really do want this to happen immediately. | |
226 | repaint(); // Use repaint rather than update because we really do want this to happen immediately. | |
237 | 227 | } |
238 | 228 | |
239 | 229 | void MutatableImageDisplay::image_function(const boost::shared_ptr<const MutatableImage>& i,bool one_of_many) |
259 | 249 | { |
260 | 250 | // Clear any existing image data - stops old animations continuing to play |
261 | 251 | for (uint f=0;f<_offscreen_pixmaps.size();f++) |
262 | _offscreen_pixmaps[f].fill(black); | |
252 | _offscreen_pixmaps[f].fill(QColor(0,0,0)); | |
263 | 253 | |
264 | 254 | // Queue a redraw |
265 | 255 | update(); |
274 | 264 | _offscreen_images_inbox.clear(); |
275 | 265 | |
276 | 266 | // Update lock status displayed in menu |
277 | _menu->setItemChecked(_menu_item_number_lock,(_image_function.get() ? _image_function->locked() : false)); | |
267 | if (_menu_item_action_lock) | |
268 | _menu_item_action_lock->setChecked(_image_function.get() ? _image_function->locked() : false); | |
278 | 269 | |
279 | 270 | if (_image_function.get()) |
280 | 271 | { |
395 | 386 | _offscreen_images.resize(0); |
396 | 387 | for (uint f=0;f<_frames;f++) |
397 | 388 | { |
398 | _offscreen_images.push_back(QImage(render_size,32)); | |
389 | _offscreen_images.push_back(QImage(render_size,QImage::Format_RGB32)); | |
399 | 390 | |
400 | 391 | for (OffscreenImageInbox::mapped_type::const_iterator it=inbox_level.begin();it!=inbox_level.end();++it) |
401 | 392 | { |
402 | bitBlt | |
393 | QPainter painter(&_offscreen_images.back()); | |
394 | painter.drawImage | |
403 | 395 | ( |
404 | &_offscreen_images.back(), | |
405 | (*it).second->fragment_origin().width(),(*it).second->fragment_origin().height(), | |
406 | &(*it).second->images()[f], | |
407 | 0,0, | |
408 | (*it).second->fragment_size().width(),(*it).second->fragment_size().height(), | |
409 | 0 | |
396 | QPoint((*it).second->fragment_origin().width(),(*it).second->fragment_origin().height()), | |
397 | (*it).second->images()[f] | |
410 | 398 | ); |
411 | 399 | } |
412 | 400 | } |
414 | 402 | |
415 | 403 | for (uint f=0;f<_frames;f++) |
416 | 404 | { |
417 | //! \todo Pick a scaling mode: smooth or not (or put it under GUI control). | |
418 | // Curiously, although smoothscale seems to be noticeably slower, it doesn't look any better. | |
419 | _offscreen_pixmaps[f].convertFromImage(_offscreen_images[f].scale(image_size())); | |
405 | //! \todo Pick a scaling mode: Qt::SmoothTransformation vs Qt::FastTransformation (default) (and put it under GUI control). | |
406 | //! \todo Expose dither mode control: Qt::DiffuseDither vs Qt::ThresholdDither | |
407 | _offscreen_pixmaps[f]=QPixmap::fromImage(_offscreen_images[f].scaled(image_size()),(Qt::ColorOnly|Qt::ThresholdDither)); | |
420 | 408 | } |
421 | 409 | |
422 | 410 | //! Note the resolution we've displayed so out-of-order low resolution images are dropped |
424 | 412 | _current_display_multisample_grid=task->multisample_grid(); |
425 | 413 | |
426 | 414 | // For an icon, take the first image big enough to (hopefully) be filtered down nicely. |
427 | // The converter seems to auto-create an alpha mask sometimes (images with const-color areas), which is quite cool. | |
415 | // The (Qt3) converter seems to auto-create an alpha mask sometimes (images with const-color areas), which is quite cool. | |
428 | 416 | const QSize icon_size(32,32); |
429 | 417 | if (task->serial()!=_icon_serial && (task->level()==0 || (render_size.width()>=2*icon_size.width() && render_size.height()>=2*icon_size.height()))) |
430 | 418 | { |
431 | const QImage icon_image(_offscreen_images[_offscreen_images.size()/2].smoothScale(icon_size)); | |
419 | const QImage icon_image(_offscreen_images[_offscreen_images.size()/2].scaled(icon_size)); | |
432 | 420 | |
433 | _icon=std::auto_ptr<QPixmap>(new QPixmap(icon_size)); | |
434 | _icon->convertFromImage(icon_image,QPixmap::Color); | |
421 | if (!_icon.get()) _icon=std::auto_ptr<QPixmap>(new QPixmap(icon_size)); | |
422 | (*_icon)=QPixmap::fromImage(icon_image,Qt::ColorOnly); | |
435 | 423 | |
436 | 424 | _icon_serial=task->serial(); |
437 | 425 | } |
458 | 446 | } |
459 | 447 | } |
460 | 448 | |
461 | _menu->setItemChecked(_menu_item_number_lock,l); | |
449 | _menu_item_action_lock->setChecked(l); | |
462 | 450 | } |
463 | 451 | |
464 | 452 | /*! Enlargements are implied by a non-full-functionality displays. |
471 | 459 | void MutatableImageDisplay::paintEvent(QPaintEvent*) |
472 | 460 | { |
473 | 461 | // Repaint the screen from the offscreen pixmaps |
474 | // (If there have been resizes they will be black) | |
475 | bitBlt(this,0,0,&_offscreen_pixmaps[_current_frame]); | |
462 | QPainter painter(this); | |
463 | painter.drawPixmap(0,0,_offscreen_pixmaps[_current_frame]); | |
476 | 464 | |
477 | 465 | // If this is the first paint event after a resize we can start computing images for the new size. |
478 | 466 | if (_resize_in_progress) |
500 | 488 | // Resize and reset our offscreen pixmap (something to do while we wait) |
501 | 489 | for (uint f=0;f<_offscreen_pixmaps.size();f++) |
502 | 490 | { |
503 | _offscreen_pixmaps[f].resize(image_size()); // resize destroys contents | |
504 | _offscreen_pixmaps[f].fill(black); // so set it | |
491 | _offscreen_pixmaps[f]=QPixmap(image_size()); | |
492 | _offscreen_pixmaps[f].fill(QColor(0,0,0)); | |
505 | 493 | } |
506 | 494 | |
507 | 495 | // Flag for the next paintEvent to tell it a recompute can be started now. |
511 | 499 | |
512 | 500 | void MutatableImageDisplay::mousePressEvent(QMouseEvent* event) |
513 | 501 | { |
514 | if (event->button()==RightButton) | |
502 | if (event->button()==Qt::RightButton) | |
515 | 503 | { |
516 | 504 | _menu->exec(QCursor::pos()); |
517 | 505 | } |
518 | else if (event->button()==MidButton) | |
506 | else if (event->button()==Qt::MidButton) | |
519 | 507 | { |
520 | 508 | // Take a snapshot to undo back to. |
521 | 509 | main().history().begin_action("middle-button drag"); |
525 | 513 | _mid_button_adjust_start_pos=event->pos(); |
526 | 514 | _mid_button_adjust_last_pos=event->pos(); |
527 | 515 | } |
528 | else if (_full_functionality && event->button()==LeftButton) | |
529 | { | |
530 | if (_icon.get()) _main->setIcon(*_icon); | |
516 | else if (_full_functionality && event->button()==Qt::LeftButton) | |
517 | { | |
518 | if (_icon.get()) _main->setWindowIcon(*_icon); | |
531 | 519 | |
532 | 520 | menupick_spawn(); |
533 | 521 | } |
535 | 523 | |
536 | 524 | void MutatableImageDisplay::mouseMoveEvent(QMouseEvent* event) |
537 | 525 | { |
538 | if (event->state()&MidButton) | |
526 | if (event->buttons()&Qt::MidButton) | |
539 | 527 | { |
540 | 528 | if (locked()) |
541 | 529 | { |
549 | 537 | Transform transform=TransformIdentity(); |
550 | 538 | |
551 | 539 | // Shift button (no ctrl) is various zooms |
552 | if (event->state()&ShiftButton && !(event->state()&ControlButton)) | |
540 | if (event->modifiers()&Qt::ShiftModifier && !(event->modifiers()&Qt::ControlModifier)) | |
553 | 541 | { |
554 | 542 | // Alt-Shift is anisotropic |
555 | if (event->state()&AltButton) | |
543 | if (event->modifiers()&Qt::AltModifier) | |
556 | 544 | { |
557 | 545 | // Only scale in non-degenerate cases |
558 | 546 | if ( |
600 | 588 | } |
601 | 589 | } |
602 | 590 | } |
603 | else if (event->state()&ControlButton) | |
591 | else if (event->modifiers()&Qt::ControlModifier) | |
604 | 592 | { |
605 | 593 | // Control-alt is shear |
606 | if (event->state()&AltButton) | |
594 | if (event->modifiers()&Qt::AltModifier) | |
607 | 595 | { |
608 | 596 | const real cx=image_size().width()/2.0; |
609 | 597 | const real cy=image_size().width()/2.0; |
765 | 753 | */ |
766 | 754 | void MutatableImageDisplay::menupick_save_image() |
767 | 755 | { |
768 | if (_icon.get()) _main->setIcon(*_icon); | |
756 | if (_icon.get()) _main->setWindowIcon(*_icon); | |
769 | 757 | |
770 | 758 | std::clog << "Save requested...\n"; |
771 | 759 | |
775 | 763 | } |
776 | 764 | else |
777 | 765 | { |
778 | QString save_filename=QFileDialog::getSaveFileName(".","Images (*.ppm *.png *.qt-mng)",this,"Save image","Save image to a PPM, PNG or QT-MNG file"); | |
766 | const QString save_filename=QFileDialog::getSaveFileName | |
767 | ( | |
768 | this, | |
769 | "Save image to a PNG or PPM file", | |
770 | ".", | |
771 | "Images (*.png *.ppm)" | |
772 | ); | |
773 | ||
779 | 774 | if (!save_filename.isEmpty()) |
780 | 775 | { |
781 | const char* save_format="PPM"; | |
782 | if (save_filename.upper().endsWith(".PPM")) | |
776 | QString save_format="PNG"; | |
777 | if (save_filename.toUpper().endsWith(".PPM")) | |
783 | 778 | { |
784 | 779 | save_format="PPM"; |
785 | 780 | } |
786 | else if (save_filename.upper().endsWith(".PNG")) | |
781 | else if (save_filename.toUpper().endsWith(".PNG")) | |
787 | 782 | { |
788 | 783 | save_format="PNG"; |
789 | } | |
790 | else if (save_filename.upper().endsWith(".QT-MNG")) | |
791 | { | |
792 | save_format="QT-MNG"; | |
793 | 784 | } |
794 | 785 | else |
795 | 786 | { |
797 | 788 | ( |
798 | 789 | this, |
799 | 790 | "Evolvotron", |
800 | QString("Unrecognised file suffix.\nFile will be written in ")+QString(save_format)+QString(" format.") | |
791 | QString("Unrecognised file suffix.\nFile will be written in ")+save_format+QString(" format.") | |
801 | 792 | ); |
802 | 793 | } |
803 | 794 | |
804 | if (!save_filename.isEmpty()) | |
795 | for (uint f=0;f<_offscreen_images.size();f++) | |
805 | 796 | { |
806 | std::auto_ptr<QFile> mng_file; | |
807 | if (save_format=="QT-MNG") | |
797 | QString actual_save_filename(save_filename); | |
798 | ||
799 | if (_offscreen_images.size()>1) | |
808 | 800 | { |
809 | mng_file=std::auto_ptr<QFile>(new QFile(save_filename)); | |
810 | if (!mng_file->open(IO_WriteOnly|IO_Truncate)) | |
801 | QString frame_component; | |
802 | frame_component.sprintf(".f%06d",f); | |
803 | int insert_point=save_filename.lastIndexOf(QString(".")); | |
804 | if (insert_point==-1) | |
811 | 805 | { |
812 | QMessageBox::critical(this,"Evolvotron","Failed to open file "+save_filename); | |
806 | actual_save_filename.append(frame_component); | |
813 | 807 | } |
814 | else | |
808 | else | |
815 | 809 | { |
816 | QPNGImagePacker packer(mng_file.get(),32,0); | |
817 | ||
818 | for (uint f=0;f<_offscreen_images.size();f++) | |
819 | { | |
820 | if (!packer.packImage(_offscreen_images[f])) | |
821 | { | |
822 | QMessageBox::critical(this,"Evolvotron","Failed while writing file "+save_filename+"\nFile will be removed"); | |
823 | mng_file->close(); | |
824 | if (!mng_file->remove()) | |
825 | { | |
826 | QMessageBox::critical(this,"Evolvotron","Failed to remove file "+save_filename); | |
827 | } | |
828 | break; | |
829 | } | |
830 | std::clog << "Appended frame " << f << " to " << save_filename.local8Bit() << "\n"; | |
831 | } | |
832 | ||
833 | mng_file->close(); | |
834 | if (mng_file->status()!=IO_Ok) | |
835 | { | |
836 | QMessageBox::critical(this,"Evolvotron","Failed while closing file "+save_filename+"\nFile will be removed"); | |
837 | if (!mng_file->remove()) | |
838 | { | |
839 | QMessageBox::critical(this,"Evolvotron","Failed to remove file "+save_filename); | |
840 | } | |
841 | } | |
810 | actual_save_filename.insert(insert_point,frame_component); | |
842 | 811 | } |
843 | 812 | } |
844 | else | |
813 | ||
814 | if (!_offscreen_images[f].save(actual_save_filename,save_format.toLocal8Bit())) | |
845 | 815 | { |
846 | for (uint f=0;f<_offscreen_images.size();f++) | |
816 | QMessageBox::critical(this,"Evolvotron","Failed to write file "+actual_save_filename); | |
817 | if (f<_offscreen_images.size()-1) | |
847 | 818 | { |
848 | QString actual_save_filename(save_filename); | |
849 | ||
850 | if (_offscreen_images.size()>1) | |
851 | { | |
852 | QString frame_component; | |
853 | frame_component.sprintf(".f%06d",f); | |
854 | int insert_point=save_filename.findRev(QString(".")); | |
855 | if (insert_point==-1) | |
856 | { | |
857 | actual_save_filename.append(frame_component); | |
858 | } | |
859 | else | |
860 | { | |
861 | actual_save_filename.insert(insert_point,frame_component); | |
862 | } | |
863 | } | |
864 | ||
865 | if (!_offscreen_images[f].save(actual_save_filename.local8Bit(),save_format)) | |
866 | { | |
867 | QMessageBox::critical(this,"Evolvotron","Failed to write file "+actual_save_filename); | |
868 | if (f<_offscreen_images.size()-1) | |
869 | { | |
870 | QMessageBox::critical(this,"Evolvotron","Not attempting to save remaining images in animation"); | |
871 | } | |
872 | break; | |
873 | } | |
819 | QMessageBox::critical(this,"Evolvotron","Not attempting to save remaining images in animation"); | |
874 | 820 | } |
821 | break; | |
875 | 822 | } |
876 | 823 | } |
877 | 824 | } |
881 | 828 | |
882 | 829 | void MutatableImageDisplay::menupick_save_function() |
883 | 830 | { |
884 | if (_icon.get()) _main->setIcon(*_icon); | |
885 | ||
886 | QString save_filename=QFileDialog::getSaveFileName(".","Functions (*.xml)",this,"Save function","Save image function to an XML file"); | |
831 | if (_icon.get()) _main->setWindowIcon(*_icon); | |
832 | ||
833 | const QString save_filename=QFileDialog::getSaveFileName | |
834 | ( | |
835 | this, | |
836 | "Save image function to an XML file", | |
837 | ".", | |
838 | "Functions (*.xml)" | |
839 | ); | |
840 | ||
887 | 841 | if (!save_filename.isEmpty()) |
888 | 842 | { |
889 | std::ofstream file(save_filename.local8Bit()); | |
843 | std::ofstream file(save_filename.toLocal8Bit()); | |
890 | 844 | _image_function->save_function(file); |
891 | 845 | file.flush(); |
892 | 846 | if (!file) |
898 | 852 | |
899 | 853 | void MutatableImageDisplay::menupick_load_function() |
900 | 854 | { |
901 | QString load_filename=QFileDialog::getOpenFileName(".","Functions (*.xml)",this,"Load function","Load image function from an XML file"); | |
855 | const QString load_filename=QFileDialog::getOpenFileName | |
856 | ( | |
857 | this, | |
858 | "Load image function from an XML file", | |
859 | ".", | |
860 | "Functions (*.xml)" | |
861 | ); | |
862 | ||
902 | 863 | if (!load_filename.isEmpty()) |
903 | 864 | { |
904 | std::ifstream file(load_filename.local8Bit()); | |
865 | std::ifstream file(load_filename.toLocal8Bit()); | |
905 | 866 | std::string report; |
906 | 867 | boost::shared_ptr<const MutatableImage> new_image_function(MutatableImage::load_function(_main->mutation_parameters().function_registry(),file,report)); |
907 | 868 | if (new_image_function.get()==0) |
999 | 960 | image_function()->save_function(xml); |
1000 | 961 | |
1001 | 962 | _properties->set_content(msg.str(),xml.str()); |
1002 | if (_icon.get()) _properties->setIcon(*_icon); | |
963 | if (_icon.get()) _properties->setWindowIcon(*_icon); | |
1003 | 964 | _properties->exec(); |
1004 | 965 | } |
1005 | 966 | |
1008 | 969 | */ |
1009 | 970 | void MutatableImageDisplay::spawn_big(bool scrollable,const QSize& sz) |
1010 | 971 | { |
1011 | MutatableImageDisplayBig*const top_level_widget=new MutatableImageDisplayBig(0,&main()); | |
1012 | if (_icon.get()) top_level_widget->setIcon(*_icon); | |
972 | MutatableImageDisplayBig*const top_level_widget=new MutatableImageDisplayBig(&main()); | |
973 | top_level_widget->setLayout(new QVBoxLayout); | |
974 | if (_icon.get()) top_level_widget->setWindowIcon(*_icon); | |
1013 | 975 | |
1014 | 976 | MutatableImageDisplay* display=0; |
1015 | ||
977 | ||
1016 | 978 | if (scrollable) |
1017 | 979 | { |
1018 | QScrollView*const scrollview=new QScrollView(top_level_widget,0,Qt::WDestructiveClose); | |
1019 | display=new MutatableImageDisplay(scrollview->viewport(),&main(),false,true,sz,_frames,_framerate); | |
1020 | scrollview->addChild(display); | |
1021 | top_level_widget->hold(scrollview); | |
980 | QScrollArea*const scrollview=new QScrollArea; | |
981 | top_level_widget->layout()->addWidget(scrollview); | |
982 | display=new MutatableImageDisplay(&main(),false,true,sz,_frames,_framerate); | |
983 | scrollview->setWidget(display); | |
1022 | 984 | } |
1023 | 985 | else |
1024 | 986 | { |
1025 | display=new MutatableImageDisplay(top_level_widget,&main(),false,false,QSize(0,0),_frames,_framerate); | |
1026 | top_level_widget->hold(display); | |
987 | display=new MutatableImageDisplay(&main(),false,false,QSize(0,0),_frames,_framerate); | |
988 | top_level_widget->layout()->addWidget(display); | |
1027 | 989 | } |
1028 | 990 | |
1029 | 991 | top_level_widget->show(); |
22 | 22 | #ifndef _mutatable_image_display_h_ |
23 | 23 | #define _mutatable_image_display_h_ |
24 | 24 | |
25 | #include <qpixmap.h> | |
26 | #include <qpopupmenu.h> | |
27 | ||
28 | 25 | #include "mutatable_image.h" |
29 | 26 | #include "mutatable_image_computer.h" |
30 | 27 | #include "dialog_mutatable_image_display.h" |
45 | 42 | EvolvotronMain* _main; |
46 | 43 | |
47 | 44 | //! Flag for whether context menu should display all options. |
45 | /*! false also implies a standalone window | |
46 | */ | |
48 | 47 | const bool _full_functionality; |
49 | 48 | |
50 | 49 | //! Flag for whether the offscreen buffer has fixed size |
113 | 112 | DialogMutatableImageDisplay* _properties; |
114 | 113 | |
115 | 114 | //! Context (right-click) menu. |
116 | QPopupMenu* _menu; | |
115 | QMenu* _menu; | |
117 | 116 | |
118 | 117 | //! Submenu for spawn warped options. |
119 | QPopupMenu* _menu_warped; | |
118 | QMenu* _menu_warped; | |
120 | 119 | |
121 | 120 | //! Submenu for Big image options. |
122 | QPopupMenu* _menu_big; | |
121 | QMenu* _menu_big; | |
123 | 122 | |
124 | 123 | //! Position of item in menu. |
125 | 124 | /*! This is the only menu item we need to retain this information for becuase we need it to set the lock check-mark. |
126 | 125 | */ |
127 | uint _menu_item_number_lock; | |
126 | QAction* _menu_item_action_lock; | |
128 | 127 | |
129 | 128 | //! Coordinate of mouse event which started mid-button adjustment |
130 | 129 | QPoint _mid_button_adjust_start_pos; |
137 | 136 | |
138 | 137 | public: |
139 | 138 | //! Constructor. |
140 | MutatableImageDisplay(QWidget* parent,EvolvotronMain* mn,bool full,bool fixed_size,const QSize& image_size,uint f,uint fr); | |
139 | MutatableImageDisplay(EvolvotronMain* mn,bool full_functionality,bool fixed_size,const QSize& image_size,uint f,uint fr); | |
141 | 140 | |
142 | 141 | //! Destructor. |
143 | 142 | virtual ~MutatableImageDisplay(); |
149 | 148 | } |
150 | 149 | |
151 | 150 | //! Accessor. |
152 | const bool locked() const | |
151 | bool locked() const | |
153 | 152 | { |
154 | 153 | return (_image_function.get()!=0 ? _image_function->locked() : false); |
155 | 154 | } |
205 | 204 | public slots: |
206 | 205 | |
207 | 206 | //! Simplify the held image, return the number of nodes eliminated |
208 | const uint simplify_constants(bool single); | |
207 | uint simplify_constants(bool single); | |
209 | 208 | |
210 | 209 | protected slots: |
211 | 210 |
26 | 26 | |
27 | 27 | #include "evolvotron_main.h" |
28 | 28 | |
29 | /*! The constructor is passed: | |
30 | - the owning widget (expected to be null but it might get used somewhere else one day) | |
31 | - the EvolvotronMain providing spawn and farm services, | |
32 | - the MutatableImageDisplay to be held | |
33 | */ | |
34 | MutatableImageDisplayBig::MutatableImageDisplayBig(QWidget* parent,EvolvotronMain* mn) | |
35 | :QWidget(parent,0,Qt::WDestructiveClose) | |
36 | ,_main(mn) | |
37 | ,_held(0) | |
38 | {} | |
29 | MutatableImageDisplayBig::MutatableImageDisplayBig(EvolvotronMain* mn) | |
30 | :QWidget(mn,Qt::Window) // We're a window, but with a parent | |
31 | ,_main(mn) | |
32 | { | |
33 | setAttribute(Qt::WA_DeleteOnClose,true); | |
34 | ||
35 | setWindowTitle("Evolvotron"); | |
36 | setMinimumSize(256,256); | |
37 | ||
38 | //setSizeGripEnabled(true); // Only an option if we give the window a statusbar, or make it a dialog | |
39 | } | |
39 | 40 | |
40 | 41 | /*! Don't think destructor needs to do anything to _display... Qt takes care of it |
41 | 42 | */ |
42 | 43 | MutatableImageDisplayBig::~MutatableImageDisplayBig() |
43 | {} | |
44 | { | |
45 | std::clog << "An enlargement was deleted\n"; | |
46 | } | |
44 | 47 | |
45 | 48 | /*! There's not much point in dropping back to normal mode (from fullscreen) if the main |
46 | 49 | app is fullscreen because we'll just be hidden, so close instead under such circumstances. |
55 | 58 | else |
56 | 59 | showNormal(); |
57 | 60 | } |
58 | else if (e->key()==Qt::Key_F && !(e->state()^Qt::ControlButton)) | |
61 | else if (e->key()==Qt::Key_F && !e->modifiers()) | |
59 | 62 | { |
60 | 63 | if (isFullScreen()) |
61 | 64 | { |
72 | 75 | e->ignore(); |
73 | 76 | } |
74 | 77 | } |
75 | ||
76 | void MutatableImageDisplayBig::resizeEvent(QResizeEvent*) | |
77 | { | |
78 | _held->resize(size()); | |
79 | } |
0 | 0 | // Source file for evolvotron |
1 | // Copyright (C) 2002,2003 Tim Day | |
1 | // Copyright (C) 2009 Tim Day | |
2 | 2 | /* |
3 | 3 | This program is free software; you can redistribute it and/or |
4 | 4 | modify it under the terms of the GNU General Public License |
27 | 27 | //! Intended to be used as a top-level widget holding a single MutatableImageDisplay |
28 | 28 | /*! We just used to use a display or scroll view itself as a top-level widget, |
29 | 29 | but need this to get some specific keyboard effects. |
30 | As a MutatableImageDisplayHolder it actually has more in common with EvolvotronMain. | |
31 | 30 | \todo class name is a bit misleading. This is really just a slightly modified top-level holder. |
32 | 31 | */ |
33 | 32 | class MutatableImageDisplayBig : public QWidget |
35 | 34 | Q_OBJECT |
36 | 35 | |
37 | 36 | protected: |
38 | //! Pointer back to the application object to access services. | |
37 | //! Pointer back to the application object to access fullscreen state | |
39 | 38 | EvolvotronMain* _main; |
40 | ||
41 | //! The widget being held. Probably be a QScrollView or MutatableImageDisplay. | |
42 | QWidget* _held; | |
43 | 39 | |
44 | 40 | public: |
45 | 41 | //! Constructor. |
46 | MutatableImageDisplayBig(QWidget* parent,EvolvotronMain* mn); | |
42 | MutatableImageDisplayBig(EvolvotronMain* mn); | |
47 | 43 | |
48 | 44 | //! Destructor. |
49 | 45 | virtual ~MutatableImageDisplayBig(); |
50 | 46 | |
51 | 47 | //! Accessor. |
52 | EvolvotronMain*const main() const | |
48 | EvolvotronMain* main() const | |
53 | 49 | { |
54 | 50 | assert(_main!=0); |
55 | 51 | return _main; |
56 | 52 | } |
57 | 53 | |
58 | //! Accessor. | |
59 | void hold(QWidget* w) | |
60 | { | |
61 | _held=w; | |
62 | } | |
63 | ||
64 | 54 | protected: |
65 | 55 | //! Handle key-presses |
66 | 56 | void keyPressEvent(QKeyEvent* e); |
67 | ||
68 | //! Need to propagate resizes to held widget | |
69 | virtual void resizeEvent(QResizeEvent*); | |
70 | 57 | }; |
71 | 58 | |
72 | 59 | #endif |
0 | // Source file for evolvotron | |
1 | // Copyright (C) 2008 Tim Day | |
2 | /*! \page License License | |
3 | ||
4 | This program is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU General Public License | |
6 | as published by the Free Software Foundation; either version 2 | |
7 | of the License, or (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
17 | */ | |
18 | ||
19 | /*! \file | |
20 | \brief Implementation of platform specific functions. | |
21 | */ | |
22 | ||
23 | #include "libevolvotron_precompiled.h" | |
24 | ||
25 | #include "platform_specific.h" | |
26 | ||
27 | #ifdef PLATFORM_LINUX | |
28 | #include <sched.h> // for CPU count | |
29 | #include <sys/resource.h> // for getpriority/setprioirty | |
30 | #endif | |
31 | ||
32 | #ifdef PLATFORM_BSD | |
33 | #include <sys/param.h> // for CPU count | |
34 | #include <sys/sysctl.h> // for CPU count | |
35 | #include <sys/resource.h> // for getpriority/setprioirty | |
36 | #endif | |
37 | ||
38 | uint get_number_of_processors() | |
39 | { | |
40 | boost::optional<uint> num_processors; | |
41 | ||
42 | #ifdef PLATFORM_LINUX | |
43 | { | |
44 | cpu_set_t cpus; | |
45 | if (sched_getaffinity(0,sizeof(cpu_set_t),&cpus)==0) | |
46 | { | |
47 | uint bits=0; | |
48 | for (int i=0;i<CPU_SETSIZE;i++) | |
49 | { | |
50 | if (CPU_ISSET(i,&cpus)) bits++; | |
51 | } | |
52 | num_processors=bits; | |
53 | } | |
54 | } | |
55 | #endif | |
56 | ||
57 | #ifdef PLATFORM_BSD | |
58 | { | |
59 | // Code contributed by Linc Davis | |
60 | int count; | |
61 | size_t size=sizeof(count); | |
62 | if (!sysctlbyname("hw.ncpu",&count,&size,NULL,0)) | |
63 | num_processors=count; | |
64 | } | |
65 | #endif | |
66 | ||
67 | #if !defined(PLATFORM_LINUX) && !defined(PLATFORM_BSD) | |
68 | #warning "No platform-specific implementation of get_number_of_processors selected" | |
69 | #endif | |
70 | ||
71 | if (!num_processors) | |
72 | { | |
73 | // If we can't find out... well, 2 is not uncommon these days. | |
74 | num_processors=2; | |
75 | std::cerr | |
76 | << "Could not determine number of CPUs; guessing " | |
77 | << num_processors.get() | |
78 | << "\n"; | |
79 | //! todo For real fun, test the system and see what it scales to. | |
80 | } | |
81 | ||
82 | return num_processors.get(); | |
83 | } | |
84 | ||
85 | void add_thread_niceness(uint n) | |
86 | { | |
87 | #if defined(PLATFORM_LINUX) || defined(PLATFORM_BSD) | |
88 | /*! \todo: People porting to non-Linux (BSD, MacOS, Fink etc) please send | |
89 | a suitable #ifdef-able patch if you need something different here. | |
90 | Note that this code relies on Linux NPTL's non-Posix-compliant | |
91 | thread-specific nice value (although without a suitable replacement | |
92 | per-thread priority mechanism it's just as well it's that way). | |
93 | \todo: Should check some error codes, but it's probably pretty harmless if it doesn't work. | |
94 | */ | |
95 | const int current_priority=getpriority(PRIO_PROCESS,0); | |
96 | setpriority(PRIO_PROCESS,0,std::min(19u,current_priority+n)); | |
97 | #else | |
98 | #warning "No platform-specific implementation of add_thread_niceness available" | |
99 | #endif | |
100 | } |
0 | // Source file for evolvotron | |
1 | // Copyright (C) 2008 Tim Day | |
2 | /*! \page License License | |
3 | ||
4 | This program is free software; you can redistribute it and/or | |
5 | modify it under the terms of the GNU General Public License | |
6 | as published by the Free Software Foundation; either version 2 | |
7 | of the License, or (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
17 | */ | |
18 | ||
19 | /*! \file | |
20 | \brief Try to isolate platform specific code here (or rather, in the .cpp implementations) | |
21 | */ | |
22 | ||
23 | #ifndef _platform_specific_h_ | |
24 | #define _platform_specific_h_ | |
25 | ||
26 | // qt3 for Darwin appears to define this, so use it to definitely select the PLATFORM_BSD option | |
27 | #ifdef __DARWIN_X11__ | |
28 | #define PLATFORM_BSD | |
29 | #undef PLATFORM_LINUX | |
30 | #endif | |
31 | ||
32 | //! Return the number of processors on the system | |
33 | extern uint get_number_of_processors(); | |
34 | ||
35 | //! Lower the priority of the calling thread by increasing its "niceness" (unix 0-19 'nice' scale used) | |
36 | extern void add_thread_niceness(uint); | |
37 | ||
38 | #endif |
22 | 22 | #ifndef _render_parameters_h_ |
23 | 23 | #define _render_parameters_h_ |
24 | 24 | |
25 | template <typename T> bool change(T& dst,const T& src) | |
26 | { | |
27 | const T previous=dst; | |
28 | dst=src; | |
29 | return (dst!=previous); | |
30 | } | |
31 | ||
25 | 32 | //! Class encapsulating things affecting rendering |
26 | 33 | class RenderParameters : public QObject |
27 | 34 | { |
32 | 39 | ~RenderParameters(); |
33 | 40 | |
34 | 41 | //! Accessor. |
35 | const bool jittered_samples() const | |
42 | bool jittered_samples() const | |
36 | 43 | { |
37 | 44 | return _jittered_samples; |
38 | 45 | } |
40 | 47 | //! Accessor. |
41 | 48 | void jittered_samples(bool v) |
42 | 49 | { |
43 | _jittered_samples=v; | |
44 | report_change(); | |
50 | if (change(_jittered_samples,v)) report_change(); | |
45 | 51 | } |
46 | 52 | |
47 | 53 | //! Accessor. |
48 | const uint multisample_grid() const | |
54 | uint multisample_grid() const | |
49 | 55 | { |
50 | 56 | assert(_multisample_grid>=1); |
51 | 57 | return _multisample_grid; |
54 | 60 | //! Accessor. |
55 | 61 | void multisample_grid(uint v) |
56 | 62 | { |
57 | _multisample_grid=v; | |
58 | assert(_multisample_grid>=1); | |
59 | report_change(); | |
63 | assert(v>=1); | |
64 | if (change(_multisample_grid,v)) report_change(); | |
60 | 65 | } |
61 | 66 | |
62 | 67 | signals: |
0 | // Source file for evolvotron | |
1 | // Copyright (C) 2002,2003,2004 Tim Day | |
2 | /* | |
3 | This program is free software; you can redistribute it and/or | |
4 | modify it under the terms of the GNU General Public License | |
5 | as published by the Free Software Foundation; either version 2 | |
6 | of the License, or (at your option) any later version. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU General Public License for more details. | |
12 | ||
13 | You should have received a copy of the GNU General Public License | |
14 | along with this program; if not, write to the Free Software | |
15 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | /*! \file | |
19 | \brief Implementation of class VBoxScrollView. | |
20 | */ | |
21 | ||
22 | #include "libevolvotron_precompiled.h" | |
23 | ||
24 | #include "vbox_scrollview.h" | |
25 | ||
26 | VBoxScrollView::VBoxScrollView(QWidget* parent) | |
27 | :QScrollView(parent) | |
28 | { | |
29 | setHScrollBarMode(QScrollView::AlwaysOff); | |
30 | enableClipper(true); | |
31 | ||
32 | QSizePolicy spx(QSizePolicy::Expanding,QSizePolicy::Preferred); | |
33 | setSizePolicy(spx); | |
34 | ||
35 | _vbox=new QVBox(viewport()); | |
36 | _vbox->setSizePolicy(spx); | |
37 | ||
38 | addChild(_vbox); | |
39 | } | |
40 | ||
41 | /*! The contained VBox is resized so it's width tracks the visible width of the scrollview. | |
42 | */ | |
43 | void VBoxScrollView::resizeEvent(QResizeEvent* e) | |
44 | { | |
45 | Superclass::resizeEvent(e); | |
46 | ||
47 | std::clog | |
48 | << "VBoxScrollView::ResizeEvent : with size " | |
49 | << size().width() << "x" << size().height() | |
50 | << " and contents size " | |
51 | << contentsWidth() << "x" << contentsHeight() | |
52 | << "\n"; | |
53 | ||
54 | _vbox->resize(visibleWidth(),_vbox->size().height()); | |
55 | } | |
56 |
0 | // Source file for evolvotron | |
1 | // Copyright (C) 2002,2003,2004 Tim Day | |
2 | /* | |
3 | This program is free software; you can redistribute it and/or | |
4 | modify it under the terms of the GNU General Public License | |
5 | as published by the Free Software Foundation; either version 2 | |
6 | of the License, or (at your option) any later version. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU General Public License for more details. | |
12 | ||
13 | You should have received a copy of the GNU General Public License | |
14 | along with this program; if not, write to the Free Software | |
15 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
16 | */ | |
17 | ||
18 | /*! \file | |
19 | \brief Interface for class VBoxScrollView. | |
20 | */ | |
21 | ||
22 | #ifndef _vbox_scrollview_h_ | |
23 | #define _vbox_scrollview_h_ | |
24 | ||
25 | #include <qscrollview.h> | |
26 | #include <qobjectlist.h> | |
27 | ||
28 | //! Scrollview containing a vbox, with the vbox width tracking the visible width of the scrolled area (height behaves as normal). | |
29 | class VBoxScrollView : public QScrollView | |
30 | { | |
31 | typedef QScrollView Superclass; | |
32 | public: | |
33 | ||
34 | //! Constructor. | |
35 | VBoxScrollView(QWidget* parent); | |
36 | ||
37 | //! Handle resizes. | |
38 | virtual void resizeEvent(QResizeEvent* e); | |
39 | ||
40 | //! Returns the VBox. Widgets which want to be managed by this component should use this as their parent. | |
41 | QWidget*const contentParent() | |
42 | { | |
43 | return _vbox; | |
44 | } | |
45 | protected: | |
46 | //! Vbox for layout within scroll area | |
47 | QVBox* _vbox; | |
48 | }; | |
49 | ||
50 | #endif |
25 | 25 | //! Functor implementing a pass-through Z coordinate policy |
26 | 26 | struct FreeZ |
27 | 27 | { |
28 | const float operator()(float z) const | |
28 | float operator()(float z) const | |
29 | 29 | { |
30 | 30 | return z; |
31 | 31 | } |
37 | 37 | ClampZ(float z) |
38 | 38 | :_z(z) |
39 | 39 | {} |
40 | const float operator()(float) const | |
40 | float operator()(float) const | |
41 | 41 | { |
42 | 42 | return _z; |
43 | 43 | } |
109 | 109 | assert(_width>0.0f); |
110 | 110 | } |
111 | 111 | |
112 | const real width() const | |
112 | real width() const | |
113 | 113 | { |
114 | 114 | return _width; |
115 | 115 | } |
43 | 43 | virtual ~FunctionBoilerplate(); |
44 | 44 | |
45 | 45 | //! Accessor providing function name |
46 | virtual const char*const thisname() const | |
46 | virtual const char* thisname() const | |
47 | 47 | =0; |
48 | 48 | |
49 | 49 | //! Registration member returns a reference to class meta-information. |
50 | 50 | static const FunctionRegistration get_registration(const char* fn_name); |
51 | 51 | |
52 | 52 | //! Bits give some classification of the function type |
53 | static const uint type_classification() {return CLASSIFICATION;} | |
53 | static uint type_classification() {return CLASSIFICATION;} | |
54 | 54 | |
55 | 55 | //! Bits give some classification of the function type |
56 | virtual const uint self_classification() const; | |
56 | virtual uint self_classification() const; | |
57 | 57 | |
58 | 58 | //! Factory method to create a stub node for this type |
59 | 59 | static std::auto_ptr<FunctionNode> stubnew(const MutationParameters& mutation_parameters,bool exciting); |
70 | 70 | std::auto_ptr<FUNCTION> typed_deepclone() const; |
71 | 71 | |
72 | 72 | //! Internal self-consistency check. We can add some extra checks. |
73 | virtual const bool ok() const; | |
73 | virtual bool ok() const; | |
74 | 74 | |
75 | 75 | //! Save this node. |
76 | 76 | virtual std::ostream& save_function(std::ostream& out,uint indent) const; |
106 | 106 | } |
107 | 107 | |
108 | 108 | template <typename FUNCTION,uint PARAMETERS,uint ARGUMENTS,bool ITERATIVE,uint CLASSIFICATION> |
109 | const uint FunctionBoilerplate<FUNCTION,PARAMETERS,ARGUMENTS,ITERATIVE,CLASSIFICATION>::self_classification() const | |
109 | uint FunctionBoilerplate<FUNCTION,PARAMETERS,ARGUMENTS,ITERATIVE,CLASSIFICATION>::self_classification() const | |
110 | 110 | { |
111 | 111 | return CLASSIFICATION; |
112 | 112 | } |
155 | 155 | } |
156 | 156 | |
157 | 157 | template <typename FUNCTION,uint PARAMETERS,uint ARGUMENTS,bool ITERATIVE,uint CLASSIFICATION> |
158 | const bool FunctionBoilerplate<FUNCTION,PARAMETERS,ARGUMENTS,ITERATIVE,CLASSIFICATION>::ok() const | |
158 | bool FunctionBoilerplate<FUNCTION,PARAMETERS,ARGUMENTS,ITERATIVE,CLASSIFICATION>::ok() const | |
159 | 159 | { |
160 | 160 | return ( |
161 | 161 | params().size()==PARAMETERS |
180 | 180 | #define FN_DTOR_DCL(FN) virtual ~FN(); |
181 | 181 | #define FN_DTOR_IMP(FN) FN::~FN() {} |
182 | 182 | |
183 | #define FN_VNAME_DCL(FN) virtual const char*const thisname() const; | |
184 | #define FN_VNAME_IMP(FN) const char*const FN::thisname() const {return FN::classname();} | |
185 | ||
186 | #define FN_SNAME_DCL(FN) static const char*const classname(); | |
187 | #define FN_SNAME_IMP(FN) const char*const FN::classname() {return #FN;} | |
183 | #define FN_VNAME_DCL(FN) virtual const char* thisname() const; | |
184 | #define FN_VNAME_IMP(FN) const char* FN::thisname() const {return FN::classname();} | |
185 | ||
186 | #define FN_SNAME_DCL(FN) static const char* classname(); | |
187 | #define FN_SNAME_IMP(FN) const char* FN::classname() {return #FN;} | |
188 | 188 | |
189 | 189 | #define FUNCTION_BEGIN(FN,NP,NA,IT,CL) \ |
190 | 190 | class FN : public FunctionBoilerplate<FN,NP,NA,IT,CL> \ |
33 | 33 | //! Is constant if any (rather than default "all") function is constant. |
34 | 34 | /*! One of the few cases it's worth overriding this method |
35 | 35 | */ |
36 | virtual const bool is_constant() const | |
36 | virtual bool is_constant() const | |
37 | 37 | { |
38 | 38 | return (arg(0).is_constant() || arg(1).is_constant()); |
39 | 39 | } |
33 | 33 | //! Is constant if any (rather than default "all") function is constant. |
34 | 34 | /*! One of the few cases it's worth overriding this method |
35 | 35 | */ |
36 | virtual const bool is_constant() const | |
36 | virtual bool is_constant() const | |
37 | 37 | { |
38 | 38 | return (arg(0).is_constant() || arg(1).is_constant() || arg(2).is_constant()); |
39 | 39 | } |
22 | 22 | #ifndef _function_constant_h_ |
23 | 23 | #define _function_constant_h_ |
24 | 24 | |
25 | ||
26 | ||
27 | 25 | //------------------------------------------------------------------------------------------ |
28 | 26 | |
29 | 27 | //! Function class representing a constant value. |
38 | 36 | //! Returns true, obviously. |
39 | 37 | /*! One of the few cases this method is overriden; most (all?) other no-argument functions should return false |
40 | 38 | */ |
41 | virtual const bool is_constant() const | |
39 | virtual bool is_constant() const | |
42 | 40 | { |
43 | 41 | return true; |
44 | 42 | } |
23 | 23 | #ifndef _function_identity_h_ |
24 | 24 | #define _function_identity_h_ |
25 | 25 | |
26 | //------------------------------------------------------------------------------------------ | |
26 | 27 | |
27 | 28 | //! Function class simply returning the position argument. |
28 | 29 | FUNCTION_BEGIN(FunctionIdentity,0,0,false,FnCore) |
97 | 97 | } |
98 | 98 | } |
99 | 99 | |
100 | const bool FunctionNode::verify_info(const FunctionNodeInfo& info,unsigned int np,unsigned int na,bool it,std::string& report) | |
100 | bool FunctionNode::verify_info(const FunctionNodeInfo& info,unsigned int np,unsigned int na,bool it,std::string& report) | |
101 | 101 | { |
102 | 102 | if (info.params().size()!=np) |
103 | 103 | { |
130 | 130 | return true; |
131 | 131 | } |
132 | 132 | |
133 | const bool FunctionNode::is_constant() const | |
133 | bool FunctionNode::is_constant() const | |
134 | 134 | { |
135 | 135 | if (args().empty()) return false; |
136 | 136 | for (unsigned int i=0;i<args().size();i++) |
140 | 140 | return true; |
141 | 141 | } |
142 | 142 | |
143 | const bool FunctionNode::ok() const | |
143 | bool FunctionNode::ok() const | |
144 | 144 | { |
145 | 145 | bool good=true; |
146 | 146 | for (boost::ptr_vector<FunctionNode>::const_iterator it=args().begin();good && it!=args().end();it++) |
151 | 151 | return good; |
152 | 152 | } |
153 | 153 | |
154 | const bool FunctionNode::create_args(const FunctionRegistry& function_registry,const FunctionNodeInfo& info,boost::ptr_vector<FunctionNode>& args,std::string& report) | |
154 | bool FunctionNode::create_args(const FunctionRegistry& function_registry,const FunctionNodeInfo& info,boost::ptr_vector<FunctionNode>& args,std::string& report) | |
155 | 155 | { |
156 | 156 | for (boost::ptr_vector<FunctionNodeInfo>::const_iterator it=info.args().begin();it!=info.args().end();it++) |
157 | 157 | { |
188 | 188 | v.push_back((parameters.r01() < 0.5f ? -1.0f : 1.0f)*parameters.rnegexp()); |
189 | 189 | } |
190 | 190 | |
191 | const uint FunctionNode::stubiterations(const MutationParameters& parameters) | |
191 | uint FunctionNode::stubiterations(const MutationParameters& parameters) | |
192 | 192 | { |
193 | 193 | return 1+static_cast<uint>(floor(parameters.r01()*parameters.max_initial_iterations())); |
194 | 194 | } |
398 | 398 | return ret; |
399 | 399 | } |
400 | 400 | |
401 | const FunctionTop*const FunctionNode::is_a_FunctionTop() const | |
401 | const FunctionTop* FunctionNode::is_a_FunctionTop() const | |
402 | 402 | { |
403 | 403 | return 0; |
404 | 404 | } |
405 | 405 | |
406 | FunctionTop*const FunctionNode::is_a_FunctionTop() | |
406 | FunctionTop* FunctionNode::is_a_FunctionTop() | |
407 | 407 | { |
408 | 408 | return 0; |
409 | 409 | } |
89 | 89 | /*! Return true on success, false on fail with reasons in report string. |
90 | 90 | Mainly for use by derived FunctionBoilerplate template to avoid duplicate code proliferation. |
91 | 91 | */ |
92 | static const bool verify_info(const FunctionNodeInfo& info,unsigned int np,unsigned int na,bool it,std::string& report); | |
92 | static bool verify_info(const FunctionNodeInfo& info,unsigned int np,unsigned int na,bool it,std::string& report); | |
93 | 93 | |
94 | 94 | //! Build argument list. |
95 | 95 | /*! Return true on success, false on fail with reasons in report string. |
96 | 96 | Mainly for use by derived FunctionBoilerplate template to avoid duplicate code proliferation. |
97 | 97 | */ |
98 | static const bool create_args(const FunctionRegistry&,const FunctionNodeInfo& info,boost::ptr_vector<FunctionNode>& args,std::string& report); | |
98 | static bool create_args(const FunctionRegistry&,const FunctionNodeInfo& info,boost::ptr_vector<FunctionNode>& args,std::string& report); | |
99 | 99 | |
100 | 100 | public: |
101 | 101 | |
106 | 106 | Default implementation (and probably the only sensible one) |
107 | 107 | is constant if all args are constant; no args returns false. |
108 | 108 | */ |
109 | virtual const bool is_constant() const; | |
109 | virtual bool is_constant() const; | |
110 | 110 | |
111 | 111 | //! Internal self consistency check. |
112 | virtual const bool ok() const; | |
112 | virtual bool ok() const; | |
113 | 113 | |
114 | 114 | //! Bits give some classification of the function type |
115 | virtual const uint self_classification() const | |
115 | virtual uint self_classification() const | |
116 | 116 | =0; |
117 | 117 | |
118 | 118 | //@{ |
119 | 119 | //! Query the node as to whether it is a FunctionTop (return null if not). |
120 | virtual const FunctionTop*const is_a_FunctionTop() const; | |
121 | virtual FunctionTop*const is_a_FunctionTop(); | |
120 | virtual const FunctionTop* is_a_FunctionTop() const; | |
121 | virtual FunctionTop* is_a_FunctionTop(); | |
122 | 122 | //@} |
123 | 123 | |
124 | 124 | //! This returns a new random bit of tree. Setting the "exciting" flag avoids basic node types, but only at the top level of the stub tree. |
131 | 131 | static void stubargs(boost::ptr_vector<FunctionNode>&,const MutationParameters& parameters,uint n,bool exciting=false); |
132 | 132 | |
133 | 133 | //! Return a suitable starting value for a node's iteration count (assuming it's iterative). |
134 | static const uint stubiterations(const MutationParameters& parameters); | |
134 | static uint stubiterations(const MutationParameters& parameters); | |
135 | 135 | |
136 | 136 | //! Constructor given an array of params and args and an iteration count. |
137 | 137 | /*! These MUST be provided; there are no alterative constructors. |
157 | 157 | } |
158 | 158 | |
159 | 159 | //! Accessor. |
160 | const real param(uint n) const | |
160 | real param(uint n) const | |
161 | 161 | { |
162 | 162 | assert(n<params().size()); |
163 | 163 | return params()[n]; |
164 | 164 | } |
165 | 165 | |
166 | 166 | //! Accessor. |
167 | const uint iterations() const | |
167 | uint iterations() const | |
168 | 168 | { |
169 | 169 | return _iterations; |
170 | 170 | } |
231 | 231 | protected: |
232 | 232 | //@{ |
233 | 233 | //! Useful constants used when some small sampling step is required (e.g gradient operators). |
234 | static const real epsilon() {return 1e-6;} | |
235 | static const real epsilon2() {return 2.0*epsilon();} | |
236 | static const real inv_epsilon() {return 1.0/epsilon();} | |
237 | static const real inv_epsilon2() {return 1.0/epsilon2();} | |
238 | static const real big_epsilon() {return sqrt(epsilon());} | |
234 | static real epsilon() {return 1e-6;} | |
235 | static real epsilon2() {return 2.0*epsilon();} | |
236 | static real inv_epsilon() {return 1.0/epsilon();} | |
237 | static real inv_epsilon2() {return 1.0/epsilon2();} | |
238 | static real big_epsilon() {return sqrt(epsilon());} | |
239 | 239 | //@} |
240 | 240 | }; |
241 | 241 |
73 | 73 | } |
74 | 74 | |
75 | 75 | //! Accessor. |
76 | const uint iterations() const | |
76 | uint iterations() const | |
77 | 77 | { |
78 | 78 | return _iterations; |
79 | 79 | } |
89 | 89 | } |
90 | 90 | |
91 | 91 | //! Accessor. |
92 | const FunctionNodeStubNewFnPtr stubnew_fn() const | |
92 | FunctionNodeStubNewFnPtr stubnew_fn() const | |
93 | 93 | { |
94 | 94 | return _stubnew_fn; |
95 | 95 | } |
96 | 96 | |
97 | 97 | //! Accessor. |
98 | const FunctionNodeCreateFnPtr create_fn() const | |
98 | FunctionNodeCreateFnPtr create_fn() const | |
99 | 99 | { |
100 | 100 | return _create_fn; |
101 | 101 | } |
102 | 102 | |
103 | 103 | //! Accessor. |
104 | const uint params() const | |
104 | uint params() const | |
105 | 105 | { |
106 | 106 | return _params; |
107 | 107 | } |
108 | 108 | |
109 | 109 | //! Accessor. |
110 | const uint args() const | |
110 | uint args() const | |
111 | 111 | { |
112 | 112 | return _args; |
113 | 113 | } |
114 | 114 | |
115 | 115 | //! Accessor. |
116 | const bool iterative() const | |
116 | bool iterative() const | |
117 | 117 | { |
118 | 118 | return _iterative; |
119 | 119 | } |
120 | 120 | |
121 | 121 | //! Accessor. |
122 | const uint classification() const | |
122 | uint classification() const | |
123 | 123 | { |
124 | 124 | return _classification; |
125 | 125 | } |
38 | 38 | } |
39 | 39 | |
40 | 40 | //! Return the registration for the function named (returns 0 if unknown) |
41 | const FunctionRegistration*const FunctionRegistry::lookup(const std::string& f) const | |
41 | const FunctionRegistration* FunctionRegistry::lookup(const std::string& f) const | |
42 | 42 | { |
43 | 43 | Registrations::const_iterator it=_registry_by_name.find(f); |
44 | 44 | if (it==_registry_by_name.end()) |
38 | 38 | ~FunctionRegistry(); |
39 | 39 | |
40 | 40 | //! Return the registration for the function named (returns 0 if unknown) |
41 | const FunctionRegistration*const lookup(const std::string& f) const; | |
41 | const FunctionRegistration* lookup(const std::string& f) const; | |
42 | 42 | |
43 | 43 | //! typedefed for convenience |
44 | 44 | typedef boost::ptr_map<std::string,FunctionRegistration> Registrations; |
159 | 159 | t.concatenate_on_right(TransformScale(2.0)); |
160 | 160 | } |
161 | 161 | while (parameters.r01()<0.125); |
162 | while (parameters.r01()<0.125); | |
162 | ||
163 | while (parameters.r01()<0.125) | |
163 | 164 | { |
164 | 165 | t.concatenate_on_right(TransformScale(0.5)); |
165 | 166 | } |
38 | 38 | |
39 | 39 | virtual const XYZ evaluate(const XYZ& p) const; |
40 | 40 | |
41 | virtual FunctionTop*const is_a_FunctionTop() | |
41 | virtual FunctionTop* is_a_FunctionTop() | |
42 | 42 | { |
43 | 43 | return this; |
44 | 44 | } |
45 | 45 | |
46 | virtual const FunctionTop*const is_a_FunctionTop() const | |
46 | virtual const FunctionTop* is_a_FunctionTop() const | |
47 | 47 | { |
48 | 48 | return this; |
49 | 49 | } |
21 | 21 | |
22 | 22 | #ifndef _function_transform_h_ |
23 | 23 | #define _function_transform_h_ |
24 | ||
25 | 24 | |
26 | 25 | #include "transform.h" |
27 | 26 |
23 | 23 | #ifndef _functions_juliabrot_h_ |
24 | 24 | #define _functions_juliabrot_h_ |
25 | 25 | |
26 | ||
27 | ||
28 | 26 | //------------------------------------------------------------------------------------------ |
29 | 27 | |
30 | 28 | //! Mandelbrot/Julia iterator for fractal functions. |
31 | 29 | /*! Returns i in 0 to iterations inclusive. i==iterations implies "in" set. |
32 | 30 | */ |
33 | inline const uint brot(const real z0r,const real z0i,const real cr,const real ci,const uint iterations) | |
31 | inline uint brot(const real z0r,const real z0i,const real cr,const real ci,const uint iterations) | |
34 | 32 | { |
35 | 33 | real zr=z0r; |
36 | 34 | real zi=z0i; |
60 | 60 | function_boilerplate.cpp \ |
61 | 61 | function_compose_pair.cpp \ |
62 | 62 | function_compose_triple.cpp \ |
63 | function_constant.h \ | |
64 | function_identity.h \ | |
63 | function_constant.cpp \ | |
64 | function_identity.cpp \ | |
65 | 65 | function_node.cpp \ |
66 | 66 | function_node_info.cpp \ |
67 | 67 | function_pre_transform.cpp \ |
104 | 104 | report_change(); |
105 | 105 | } |
106 | 106 | |
107 | const real MutationParameters::decay_factor() const | |
107 | real MutationParameters::decay_factor() const | |
108 | 108 | { |
109 | 109 | assert(_autocool_halflife!=0); |
110 | 110 | return (_autocool_enable ? pow(0.5,_autocool_generations/static_cast<double>(_autocool_halflife)) : 1.0); |
159 | 159 | |
160 | 160 | std::auto_ptr<FunctionNode> MutationParameters::random_function() const |
161 | 161 | { |
162 | const FunctionRegistration*const fn_reg=random_weighted_function_registration(); | |
162 | const FunctionRegistration* fn_reg=random_weighted_function_registration(); | |
163 | 163 | return (*(fn_reg->stubnew_fn()))(*this,false); |
164 | 164 | } |
165 | 165 | |
166 | const FunctionRegistration*const MutationParameters::random_weighted_function_registration() const | |
166 | const FunctionRegistration* MutationParameters::random_weighted_function_registration() const | |
167 | 167 | { |
168 | 168 | const real r=r01(); |
169 | 169 | |
180 | 180 | } |
181 | 181 | } |
182 | 182 | |
183 | const real MutationParameters::random_function_branching_ratio() const | |
183 | real MutationParameters::random_function_branching_ratio() const | |
184 | 184 | { |
185 | 185 | real weighted_args=0.0; |
186 | 186 | |
222 | 222 | report_change(); |
223 | 223 | } |
224 | 224 | |
225 | const real MutationParameters::get_weighting(const FunctionRegistration* fn) | |
225 | real MutationParameters::get_weighting(const FunctionRegistration* fn) | |
226 | 226 | { |
227 | 227 | std::map<const FunctionRegistration*,real>::const_iterator it=_function_weighting.find(fn); |
228 | 228 | assert(it!=_function_weighting.end()); |
142 | 142 | } |
143 | 143 | |
144 | 144 | //! Return a number in the range [0,1) |
145 | const real r01() const | |
145 | real r01() const | |
146 | 146 | { |
147 | 147 | return _r01(); |
148 | 148 | } |
149 | 149 | |
150 | const real rnegexp() const | |
150 | real rnegexp() const | |
151 | 151 | { |
152 | 152 | return _r_negexp(); |
153 | 153 | } |
154 | 154 | |
155 | 155 | //! Accessor, with decay. |
156 | const real effective_magnitude_parameter_variation() const | |
156 | real effective_magnitude_parameter_variation() const | |
157 | 157 | { |
158 | 158 | return base_magnitude_parameter_variation()*decay_factor(); |
159 | 159 | } |
160 | 160 | //! Accessor. |
161 | const real base_magnitude_parameter_variation() const | |
161 | real base_magnitude_parameter_variation() const | |
162 | 162 | { |
163 | 163 | return _base_magnitude_parameter_variation; |
164 | 164 | } |
170 | 170 | } |
171 | 171 | |
172 | 172 | //! Accessor, with decay. |
173 | const real effective_probability_parameter_reset() const | |
173 | real effective_probability_parameter_reset() const | |
174 | 174 | { |
175 | 175 | return base_probability_parameter_reset()*decay_factor(); |
176 | 176 | } |
177 | 177 | //! Accessor. |
178 | const real base_probability_parameter_reset() const | |
178 | real base_probability_parameter_reset() const | |
179 | 179 | { |
180 | 180 | return _base_probability_parameter_reset; |
181 | 181 | } |
187 | 187 | } |
188 | 188 | |
189 | 189 | //! Accessor, with decay. |
190 | const real effective_probability_glitch() const | |
190 | real effective_probability_glitch() const | |
191 | 191 | { |
192 | 192 | return base_probability_glitch()*decay_factor(); |
193 | 193 | } |
194 | 194 | //! Accessor. |
195 | const real base_probability_glitch() const | |
195 | real base_probability_glitch() const | |
196 | 196 | { |
197 | 197 | return _base_probability_glitch; |
198 | 198 | } |
204 | 204 | } |
205 | 205 | |
206 | 206 | //! Accessor, with decay. |
207 | const real effective_probability_shuffle() const | |
207 | real effective_probability_shuffle() const | |
208 | 208 | { |
209 | 209 | return base_probability_shuffle()*decay_factor(); |
210 | 210 | } |
211 | 211 | //! Accessor. |
212 | const real base_probability_shuffle() const | |
212 | real base_probability_shuffle() const | |
213 | 213 | { |
214 | 214 | return _base_probability_shuffle; |
215 | 215 | } |
221 | 221 | } |
222 | 222 | |
223 | 223 | //! Accessor, with decay. |
224 | const real effective_probability_insert() const | |
224 | real effective_probability_insert() const | |
225 | 225 | { |
226 | 226 | return base_probability_insert()*decay_factor(); |
227 | 227 | } |
228 | 228 | //! Accessor. |
229 | const real base_probability_insert() const | |
229 | real base_probability_insert() const | |
230 | 230 | { |
231 | 231 | return _base_probability_insert; |
232 | 232 | } |
238 | 238 | } |
239 | 239 | |
240 | 240 | //! Accessor. |
241 | const real effective_probability_substitute() const | |
241 | real effective_probability_substitute() const | |
242 | 242 | { |
243 | 243 | return base_probability_substitute()*decay_factor(); |
244 | 244 | } |
245 | 245 | //! Accessor. |
246 | const real base_probability_substitute() const | |
246 | real base_probability_substitute() const | |
247 | 247 | { |
248 | 248 | return _base_probability_substitute; |
249 | 249 | } |
255 | 255 | } |
256 | 256 | |
257 | 257 | //! Accessor. |
258 | const real proportion_constant() const | |
258 | real proportion_constant() const | |
259 | 259 | { |
260 | 260 | return _proportion_constant; |
261 | 261 | } |
267 | 267 | } |
268 | 268 | |
269 | 269 | //! Accessor. |
270 | const real identity_supression() const | |
270 | real identity_supression() const | |
271 | 271 | { |
272 | 272 | return _identity_supression; |
273 | 273 | } |
279 | 279 | } |
280 | 280 | |
281 | 281 | //! Accessor. |
282 | const uint max_initial_iterations() const | |
282 | uint max_initial_iterations() const | |
283 | 283 | { |
284 | 284 | return _max_initial_iterations; |
285 | 285 | } |
291 | 291 | } |
292 | 292 | |
293 | 293 | //! Accessor, with decay. |
294 | const real effective_probability_iterations_change_step() const | |
294 | real effective_probability_iterations_change_step() const | |
295 | 295 | { |
296 | 296 | return base_probability_iterations_change_step()*decay_factor(); |
297 | 297 | } |
298 | 298 | //! Accessor. |
299 | const real base_probability_iterations_change_step() const | |
299 | real base_probability_iterations_change_step() const | |
300 | 300 | { |
301 | 301 | return _base_probability_iterations_change_step; |
302 | 302 | } |
308 | 308 | } |
309 | 309 | |
310 | 310 | //! Accessor, with decay. |
311 | const real effective_probability_iterations_change_jump() const | |
311 | real effective_probability_iterations_change_jump() const | |
312 | 312 | { |
313 | 313 | return base_probability_iterations_change_jump()*decay_factor(); |
314 | 314 | } |
315 | 315 | //! Accessor. |
316 | const real base_probability_iterations_change_jump() const | |
316 | real base_probability_iterations_change_jump() const | |
317 | 317 | { |
318 | 318 | return _base_probability_iterations_change_jump; |
319 | 319 | } |
325 | 325 | } |
326 | 326 | |
327 | 327 | //! Accessor. |
328 | const real proportion_basic() const | |
328 | real proportion_basic() const | |
329 | 329 | { |
330 | 330 | return _proportion_basic; |
331 | 331 | } |
337 | 337 | } |
338 | 338 | |
339 | 339 | //! Accessor. |
340 | const bool autocool_enable() const | |
340 | bool autocool_enable() const | |
341 | 341 | { |
342 | 342 | return _autocool_enable; |
343 | 343 | } |
350 | 350 | } |
351 | 351 | |
352 | 352 | //! Accessor. |
353 | const int autocool_halflife() const | |
353 | int autocool_halflife() const | |
354 | 354 | { |
355 | 355 | return _autocool_halflife; |
356 | 356 | } |
362 | 362 | } |
363 | 363 | |
364 | 364 | //! Accessor |
365 | const int autocool_generations() const | |
365 | int autocool_generations() const | |
366 | 366 | { |
367 | 367 | return _autocool_generations; |
368 | 368 | } |
382 | 382 | //! Calculate branching ratio for above calls |
383 | 383 | /* Call user should be checking this and diluting with boring nodes to keep it under control |
384 | 384 | */ |
385 | const real random_function_branching_ratio() const; | |
385 | real random_function_branching_ratio() const; | |
386 | 386 | |
387 | 387 | //! This returns a new random bit of tree. |
388 | 388 | /*! Setting the "exciting" flag avoids the most basic node types, but only at the top level of the stub tree. |
393 | 393 | |
394 | 394 | void randomize_function_weightings_for_classifications(uint classification_mask); |
395 | 395 | |
396 | const real get_weighting(const FunctionRegistration* fn); | |
396 | real get_weighting(const FunctionRegistration* fn); | |
397 | 397 | |
398 | 398 | protected: |
399 | 399 | |
400 | 400 | //! Compute current decay factor |
401 | const real decay_factor() const; | |
401 | real decay_factor() const; | |
402 | 402 | |
403 | 403 | //! Return a random function appropriately biased by current settings |
404 | 404 | std::auto_ptr<FunctionNode> random_function() const; |
405 | 405 | |
406 | 406 | //! Return a random function registration, appropriately biased by current settings |
407 | const FunctionRegistration*const random_weighted_function_registration() const; | |
407 | const FunctionRegistration* random_weighted_function_registration() const; | |
408 | 408 | |
409 | 409 | //! Intended for Qt-world subclass to override to emit signal. |
410 | 410 | virtual void report_change(); |
59 | 59 | } |
60 | 60 | } |
61 | 61 | |
62 | inline const real value(const XYZ& q,real rx,real ry,real rz) | |
62 | inline real value(const XYZ& q,real rx,real ry,real rz) | |
63 | 63 | { |
64 | 64 | return rx*q.x()+ry*q.y()+rz*q.z(); |
65 | 65 | } |
66 | 66 | |
67 | inline const real surve(real t) | |
67 | inline real surve(real t) | |
68 | 68 | { |
69 | 69 | return t*t*(3.0-2.0*t); |
70 | 70 | } |
71 | 71 | |
72 | inline const real lerp(real t,real a,real b) | |
72 | inline real lerp(real t,real a,real b) | |
73 | 73 | { |
74 | 74 | return a+t*(b-a); |
75 | 75 | } |
76 | 76 | |
77 | const real Noise::operator()(const XYZ& p) const | |
77 | real Noise::operator()(const XYZ& p) const | |
78 | 78 | { |
79 | 79 | // Crank up the frequency a bit otherwise don't see much variation in base case |
80 | 80 | const real tx=2.0*p.x()+10000.0; |
30 | 30 | Noise(uint seed); |
31 | 31 | |
32 | 32 | //! Return noise value at a point. |
33 | const real operator()(const XYZ& p) const; | |
34 | ||
33 | real operator()(const XYZ& p) const; | |
34 | ||
35 | 35 | protected: |
36 | 36 | //! Number of table entries. |
37 | 37 | enum {N=256}; |
33 | 33 | Random01::~Random01() |
34 | 34 | {} |
35 | 35 | |
36 | const double Random01::operator()() | |
36 | double Random01::operator()() | |
37 | 37 | { |
38 | 38 | return _gen(); |
39 | 39 | } |
38 | 38 | //! Return a random number. |
39 | 39 | /*! \warning Returns double instead of real because suspect NegExp can return Inf otherwise. |
40 | 40 | */ |
41 | virtual const double operator()() | |
41 | virtual double operator()() | |
42 | 42 | =0; |
43 | 43 | }; |
44 | 44 | |
53 | 53 | virtual ~Random01(); |
54 | 54 | |
55 | 55 | //! Return next number in sequence. |
56 | virtual const double operator()(); | |
56 | virtual double operator()(); | |
57 | 57 | private: |
58 | 58 | |
59 | 59 | //! Base generator |
90 | 90 | {} |
91 | 91 | |
92 | 92 | //! Return next number in sequence. |
93 | virtual const double operator()() | |
93 | virtual double operator()() | |
94 | 94 | { |
95 | 95 | return -_mean*log(1.0-_generator()); |
96 | 96 | } |
12 | 12 | REGISTER_DCL(FunctionIdentity); |
13 | 13 | REGISTER_DCL(FunctionPostTransform); |
14 | 14 | REGISTER_DCL(FunctionPreTransform); |
15 | REGISTER_DCL(FunctionTop); | |
16 | REGISTER_DCL(FunctionTransform); | |
17 | REGISTER_DCL(FunctionTransformGeneralised); | |
18 | 15 | REGISTER_DCL(FunctionAdd); |
19 | 16 | REGISTER_DCL(FunctionMultiply); |
20 | 17 | REGISTER_DCL(FunctionDivide); |
113 | 110 | REGISTER_DCL(FunctionPostTransformGeneralised); |
114 | 111 | REGISTER_DCL(FunctionTransformQuadratic); |
115 | 112 | REGISTER_DCL(FunctionRotate); |
113 | REGISTER_DCL(FunctionTop); | |
114 | REGISTER_DCL(FunctionTransformGeneralised); | |
115 | REGISTER_DCL(FunctionTransform); | |
116 | 116 | |
117 | 117 | void register_all_functions(FunctionRegistry& r) |
118 | 118 | { |
122 | 122 | register_FunctionIdentity(r); |
123 | 123 | register_FunctionPostTransform(r); |
124 | 124 | register_FunctionPreTransform(r); |
125 | register_FunctionTop(r); | |
126 | register_FunctionTransform(r); | |
127 | register_FunctionTransformGeneralised(r); | |
128 | 125 | register_FunctionAdd(r); |
129 | 126 | register_FunctionMultiply(r); |
130 | 127 | register_FunctionDivide(r); |
223 | 220 | register_FunctionPostTransformGeneralised(r); |
224 | 221 | register_FunctionTransformQuadratic(r); |
225 | 222 | register_FunctionRotate(r); |
223 | register_FunctionTop(r); | |
224 | register_FunctionTransformGeneralised(r); | |
225 | register_FunctionTransform(r); | |
226 | 226 | } |
77 | 77 | if (_verbose) std::clog << "[-" << _what << ":" << (*_instance_counts)[_what] << "]" << ( (*_instance_counts)[_what]==0 ? "\n" : ""); |
78 | 78 | } |
79 | 79 | |
80 | const bool InstanceCounted::is_clear() | |
80 | bool InstanceCounted::is_clear() | |
81 | 81 | { |
82 | 82 | bool ok=true; |
83 | 83 | for (std::map<std::string,uint>::const_iterator it=(*_instance_counts).begin();it!=(*_instance_counts).end();it++) |
23 | 23 | #define _useful_h_ |
24 | 24 | |
25 | 25 | #include <algorithm> |
26 | #include <boost/ptr_container/ptr_map.hpp> | |
27 | #include <boost/ptr_container/ptr_vector.hpp> | |
28 | #include <boost/random.hpp> | |
29 | #include <boost/shared_array.hpp> | |
30 | #include <boost/shared_ptr.hpp> | |
31 | #include <boost/tuple/tuple.hpp> | |
32 | #include <boost/utility.hpp> | |
33 | #include <boost/version.hpp> | |
34 | 26 | #include <cassert> |
35 | 27 | #include <ctime> |
36 | 28 | #include <cmath> |
45 | 37 | #include <string> |
46 | 38 | #include <sstream> |
47 | 39 | #include <vector> |
40 | ||
41 | #include <boost/ptr_container/ptr_map.hpp> | |
42 | #include <boost/ptr_container/ptr_vector.hpp> | |
43 | #include <boost/random.hpp> | |
44 | #include <boost/shared_array.hpp> | |
45 | #include <boost/shared_ptr.hpp> | |
46 | #include <boost/tuple/tuple.hpp> | |
47 | #include <boost/utility.hpp> | |
48 | #include <boost/version.hpp> | |
48 | 49 | |
49 | 50 | //! Convenience typedef. |
50 | 51 | typedef unsigned int uint; |
149 | 150 | InstanceCounted(const std::string& what,bool verbose); |
150 | 151 | virtual ~InstanceCounted(); |
151 | 152 | |
152 | static const bool is_clear(); | |
153 | static bool is_clear(); | |
153 | 154 | |
154 | 155 | private: |
155 | 156 | const std::string _what; |
34 | 34 | |
35 | 35 | //@{ |
36 | 36 | //! Accessor. |
37 | const real x() const | |
37 | real x() const | |
38 | 38 | { |
39 | 39 | return rep[0]; |
40 | 40 | } |
41 | const real y() const | |
41 | real y() const | |
42 | 42 | { |
43 | 43 | return rep[1]; |
44 | 44 | } |
121 | 121 | } |
122 | 122 | |
123 | 123 | //! Return the square of the magnitude. |
124 | const real magnitude2() const | |
124 | real magnitude2() const | |
125 | 125 | { |
126 | 126 | return x()*x()+y()*y(); |
127 | 127 | } |
128 | 128 | |
129 | 129 | //! Return the magnitude. |
130 | const real magnitude() const | |
130 | real magnitude() const | |
131 | 131 | { |
132 | 132 | return sqrt(magnitude2()); |
133 | 133 | } |
134 | 134 | |
135 | 135 | //! Returns sum of x and y components. |
136 | const real sum_of_components() const | |
136 | real sum_of_components() const | |
137 | 137 | { |
138 | 138 | return x()+y(); |
139 | 139 | } |
145 | 145 | void normalise(); |
146 | 146 | |
147 | 147 | //! Returns true if an origin centred rectangle with this vectors' semi-axes contains the argument. |
148 | const bool origin_centred_rect_contains(const XY& p) const | |
148 | bool origin_centred_rect_contains(const XY& p) const | |
149 | 149 | { |
150 | 150 | return (-x()<=p.x() && p.x()<=x() && -y()<=p.y() && p.y()<=y()); |
151 | 151 | } |
164 | 164 | //! Dot product. |
165 | 165 | /*! Perhaps a curious choice of operator but it works for me. |
166 | 166 | */ |
167 | inline const real operator%(const XY& a,const XY& b) | |
167 | inline real operator%(const XY& a,const XY& b) | |
168 | 168 | { |
169 | 169 | return a.x()*b.x()+a.y()*b.y(); |
170 | 170 | } |
224 | 224 | return v.write(out); |
225 | 225 | } |
226 | 226 | |
227 | ||
228 | 227 | #endif |
36 | 36 | |
37 | 37 | //@{ |
38 | 38 | //! Accessor. |
39 | const real x() const | |
39 | real x() const | |
40 | 40 | { |
41 | 41 | return rep[0]; |
42 | 42 | } |
43 | const real y() const | |
43 | real y() const | |
44 | 44 | { |
45 | 45 | return rep[1]; |
46 | 46 | } |
47 | const real z() const | |
47 | real z() const | |
48 | 48 | { |
49 | 49 | return rep[2]; |
50 | 50 | } |
149 | 149 | } |
150 | 150 | |
151 | 151 | //! Return the square of the magnitude. |
152 | const real magnitude2() const | |
152 | real magnitude2() const | |
153 | 153 | { |
154 | 154 | return x()*x()+y()*y()+z()*z(); |
155 | 155 | } |
156 | 156 | |
157 | 157 | //! Return the magnitude. |
158 | const real magnitude() const | |
158 | real magnitude() const | |
159 | 159 | { |
160 | 160 | return sqrt(magnitude2()); |
161 | 161 | } |
162 | 162 | |
163 | 163 | //! Returns sum of x, y and z components. |
164 | const real sum_of_components() const | |
164 | real sum_of_components() const | |
165 | 165 | { |
166 | 166 | return x()+y()+z(); |
167 | 167 | } |
173 | 173 | void normalise(); |
174 | 174 | |
175 | 175 | //! Returns true if an origin centred cuboid with this vectors semi-axes contains the argument. |
176 | const bool origin_centred_rect_contains(const XYZ& p) const | |
176 | bool origin_centred_rect_contains(const XYZ& p) const | |
177 | 177 | { |
178 | 178 | return (-x()<=p.x() && p.x()<=x() && -y()<=p.y() && p.y()<=y() && -z()<=p.z() && p.z()<=z()); |
179 | 179 | } |
186 | 186 | { |
187 | 187 | return XYZ(v,v,v); |
188 | 188 | } |
189 | ||
190 | 189 | }; |
191 | 190 | |
192 | 191 | //! Cross product. |
202 | 201 | //! Dot product. |
203 | 202 | /*! Perhaps a curious choice of operator but it works for me. |
204 | 203 | */ |
205 | inline const real operator%(const XYZ& a,const XYZ& b) | |
204 | inline real operator%(const XYZ& a,const XYZ& b) | |
206 | 205 | { |
207 | 206 | return a.x()*b.x()+a.y()*b.y()+a.z()*b.z(); |
208 | 207 | } |
294 | 293 | RandomXYZSphereNormal(Random01& rng); |
295 | 294 | }; |
296 | 295 | |
297 | ||
298 | 296 | //! Generates a random point in or on an origin-centred ellipsoid with semi-axes of the specified size. |
299 | 297 | class RandomXYZInEllipsoid : public XYZ |
300 | 298 | { |
0 | 0 | TEMPLATE = subdirs |
1 | 1 | |
2 | SUBDIRS = libfunction libevolvotron evolvotron evolvotron_render evolvotron_mutate evolvotron_match | |
2 | SUBDIRS = libfunction libevolvotron evolvotron evolvotron_render evolvotron_mutate | |
3 | 3 |
0 | #!/bin/bash | |
1 | ||
2 | # Before using this you probably need to install | |
3 | # sudo pbuilder yada devscripts lintian linda cdebootstrap | |
4 | # and maybe dpkg-sig. Also: | |
5 | # set up for sudo | |
6 | # set up pbuilder with | |
7 | # sudo emacs -nw /etc/pbuilderrc | |
8 | # ...change MIRRORSITE & DEBSECSERVER | |
9 | # sudo pbuilder create --distribution sarge/etch/whatever | |
10 | # and/or update with | |
11 | # sudo pbuilder update | |
12 | # Expect a lot of warnings re LOGNAME - see Debian bug Bug#275118 | |
13 | ||
14 | # TODO: DEBEMAIL | |
15 | ||
16 | VER=`./VERSION` | |
17 | ||
18 | TARBALL=evolvotron-${VER}.tar.gz | |
19 | ||
20 | if [ ! -s ${TARBALL} ] ; then | |
21 | echo "Could't find ${TARBALL}" ; | |
22 | exit ; | |
23 | fi | |
24 | ||
25 | export DISTRIBUTION=`lsb_release -s -c` | |
26 | ||
27 | ||
28 | echo "*** Will package ${TARBALL} for distribution \"${DISTRIBUTION}\"" | |
29 | echo -n "*** Starting in 10 seconds..." | |
30 | for t in 10 9 8 7 6 5 4 3 2 1 ; do sleep 1 ; echo -n "." ; done | |
31 | ||
32 | PROJECT=`echo $TARBALL | sed 's/-.*//'` | |
33 | TARBALLORIG="${PROJECT}_${VER}.orig.tar.gz" | |
34 | REV="1${DISTRIBUTION}1" | |
35 | ||
36 | WORKDIR=pkg_${VER}-${REV} | |
37 | rm -r -f ${WORKDIR} | |
38 | mkdir ${WORKDIR} | |
39 | cd ${WORKDIR} | |
40 | ||
41 | cp ../${TARBALL} ${TARBALLORIG} | |
42 | tar xvfz ${TARBALLORIG} | |
43 | mv ${PROJECT} ${PROJECT}-${VER} | |
44 | cd ${PROJECT}-${VER} | |
45 | mv CHANGES changelog # As per policy manual | |
46 | sed -i "s/${VER}/${VER}-${REV}/g" VERSION | |
47 | ||
48 | mkdir debian | |
49 | echo "${PROJECT} (${VER}-${REV}) ${DISTRIBUTION}; urgency=low" > debian/changelog | |
50 | echo >> debian/changelog | |
51 | echo " * Package created by ${PROJECT}'s mkdeb script." >> debian/changelog | |
52 | echo >> debian/changelog | |
53 | DATE=`822-date` | |
54 | echo " -- $USER <$EMAIL> $DATE" >> debian/changelog | |
55 | ||
56 | # Presumably a dch -i here would increment revision | |
57 | ||
58 | cat << EOF > debian/packages | |
59 | Source: evolvotron | |
60 | Section: graphics | |
61 | Priority: extra | |
62 | Maintainer: Tim Day <timday@bottlenose.demon.co.uk> | |
63 | Standards-Version: 3.6.1 | |
64 | Upstream-Source: <URL:http://sourceforge.net/projects/evolvotron/index.htm> | |
65 | Home-Page: <URL:http://www.bottlenose.demon.co.uk/share/evolvotron> | |
66 | Description: Interactive evolutionary texture generator | |
67 | Copyright: GPL | |
68 | Copyright 2007 Tim Day | |
69 | Build-Depends: qt4-qmake,qt4-dev-tools,libqt4-core,libqt4-dev,libqt4-xml,libboost1.35-dev,python,yada | |
70 | Build: sh | |
71 | export QTDIR=/usr/share/qt4 | |
72 | # Note: yada install deals with DEB_BUILD_OPTIONS 'nostrip' | |
73 | if [ "${DEB_BUILD_OPTIONS#*noopt}" != "$DEB_BUILD_OPTIONS" ]; then | |
74 | ./configure "CONFIG -= release" "CONFIG += debug" | |
75 | else | |
76 | ./configure # No noticeable advantage in overriding qt optimisation options | |
77 | fi | |
78 | make | |
79 | Clean: sh | |
80 | make distclean || make clean || true | |
81 | ||
82 | Package: evolvotron | |
83 | Architecture: any | |
84 | Depends: [] | |
85 | Suggests: gimp | |
86 | Description: Interactive evolutionary texture generator | |
87 | A "generative art" application to evolve images/textures/patterns through an | |
88 | iterative process of random mutation and user-selection driven evolution. | |
89 | If you like lava lamps, and never got bored with the Mandelbrot Set, | |
90 | this could be the software for you. | |
91 | Install: sh | |
92 | yada install -bin evolvotron/evolvotron | |
93 | yada install -bin evolvotron_mutate/evolvotron_mutate | |
94 | yada install -bin evolvotron_render/evolvotron_render | |
95 | yada install -bin evolvotron/evolvotron | |
96 | yada install -doc evolvotron.html | |
97 | yada install -doc BUGS TODO changelog | |
98 | yada install -man man/man1/evolvotron.1 | |
99 | yada install -man man/man1/evolvotron_mutate.1 | |
100 | yada install -man man/man1/evolvotron_render.1 | |
101 | Menu: ?package(evolvotron): needs="X11" section="Applications/Graphics" title="Evolvotron" hints="Bitmap" command="/usr/bin/evolvotron" longtitle="Evolutionary art program" | |
102 | EOF | |
103 | ||
104 | yada rebuild | |
105 | ||
106 | cd .. | |
107 | dpkg-source -b ${PROJECT}-${VER} ${TARBALLORIG} | |
108 | ||
109 | # Alternative but inferior approach is apparently to do | |
110 | # dpkg-buildpackage -rfakeroot | |
111 | ||
112 | mkdir result | |
113 | echo "Building package" | |
114 | sudo pbuilder build --buildresult ./result ${PROJECT}_${VER}-${REV}.dsc | |
115 | ||
116 | sudo chown ${USER}:${USER} result/* | |
117 | ||
118 | RESULT=`(cd .. ; find ${WORKDIR} -name '*.deb')` | |
119 | echo "Results: ${RESULT}" | |
120 | echo "Don't forget to lintian and linda" | |
121 | echo 'Also dpkg-sig --sign builder -k $DPKGSIG_KEYID any .deb files' | |
122 |
8 | 8 | # NB Don't ship automatically generated .h file or contents of pkg |
9 | 9 | PRUNE='-name moc -prune -o -name obj -prune -o -name pkg_* -prune -o -name usage_text.h -prune' |
10 | 10 | |
11 | FILES_MISC=`ls evolvotron/{README,BUILD,LICENSE,TODO,CHANGES,VERSION,USAGE,BUGS,configure,doxygen.cfg,mktgz,mkdoc,text_to_markup.py} evolvotron/libfunction/update_register_all_functions` | |
12 | FILES_EXTRAS=`ls evolvotron/extras/{README,spheremap.pov,spheremap.sh}` | |
11 | FILES_MISC=`ls evolvotron/{README,BUILD,LICENSE,TODO,CHANGES,VERSION,USAGE,BUGS,configure,doxygen.cfg,mktgz,mkdeb,mkdoc,text_to_markup.py} evolvotron/libfunction/update_register_all_functions` | |
12 | FILES_EXTRAS="`ls evolvotron/extras/{README,spheremap.pov,spheremap.sh}` `ls evolvotron/rpm/{README,evolvotron.spec}`" | |
13 | 13 | |
14 | 14 | FILES_H=`find evolvotron ${PRUNE} -o -name '*.h' -print` |
15 | 15 | FILES_CPP=`find evolvotron ${PRUNE} -o -name '*.cpp' -print` |
23 | 23 | echo "***" |
24 | 24 | echo "*** Suggestion: mv evolvotron.tar.gz evolvotron-$VERSION.tar.gz" |
25 | 25 | echo "***" |
26 | ||
27 |
0 | This directory contains contributed RPM packaging related resources. | |
1 | ||
2 | ----- | |
3 | ||
4 | evolvotron.spec | |
5 | - Karl Robillard's .spec file to build RPM packages on Mandriva, Fedora and Suse. | |
6 | ||
7 | ----- | |
8 | See | |
9 | http://www.bottlenose.demon.co.uk/share/evolvotron/download.htm | |
10 | for up-to-date news re downloadable packages. |
0 | Summary: Evolvotron Interactive Art Generator | |
1 | Name: evolvotron | |
2 | Version: 0.5.1 | |
3 | Release: 1 | |
4 | License: GPL | |
5 | URL: http://sourceforge.net/projects/evolvotron | |
6 | Packager: <wickedsmoke@users.sf.net> | |
7 | Group: Applications/Graphics | |
8 | Source: %{name}-%{version}.tar.gz | |
9 | BuildRoot: %{_tmppath}/%{name}-%{version}-build | |
10 | %if 0%{?fedora_version} | |
11 | BuildRequires: gcc-c++ boost-devel python qt-devel | |
12 | %else | |
13 | BuildRequires: gcc-c++ boost-devel python qt3-devel | |
14 | %endif | |
15 | ||
16 | %description | |
17 | Evolvotron is interactive "generative art" software to evolve images/textures/patterns through an iterative process of random mutation and user-selection driven evolution. | |
18 | ||
19 | %prep | |
20 | %setup -q -n %{name} | |
21 | ||
22 | %build | |
23 | %if 0%{?fedora_version} | |
24 | source /etc/profile.d/qt.sh | |
25 | %endif | |
26 | %if 0%{?mandriva_version} | |
27 | export QTDIR=%{_prefix}/lib/qt3 | |
28 | export PATH=$QTDIR/bin:$PATH | |
29 | %endif | |
30 | %if 0%{?suse_version} | |
31 | export QTDIR=/usr/%{_lib}/qt3 | |
32 | export PATH=$QTDIR/bin:$PATH | |
33 | %endif | |
34 | ./configure | |
35 | make | |
36 | ||
37 | %install | |
38 | # make install | |
39 | mkdir -p $RPM_BUILD_ROOT/usr/bin | |
40 | install -s -m 755 evolvotron/evolvotron $RPM_BUILD_ROOT/usr/bin | |
41 | ||
42 | %clean | |
43 | rm -rf $RPM_BUILD_ROOT | |
44 | ||
45 | %files | |
46 | %defattr(-,root,root) | |
47 | /usr/bin/evolvotron | |
48 | %doc README USAGE CHANGES | |
49 | ||
50 | %changelog | |
51 | * Fri Mar 28 2008 Karl Robillard <wickedsmoke@users.sf.net> | |
52 | - Initial package release. |