1 #include <cctype>
2 #include <cstdlib>
3 #include <climits>
4 #include <cmath>
5 #include <cstring>
6 #include <cerrno>
7 #ifdef DEBUG
8 #ifdef __linux__
9 #define MEMCHECK
10 #include <malloc.h>
11 #endif
12 #endif
13
14 #include "config.h"
15 #include "filter.h"
16 #include "ui_helper.h"
17 #include "plane.h"
18 #include "timers.h"
19 #include "zoom.h"
20 #include "xmenu.h"
21 #include "xerror.h"
22 #include "autopilot.h"
23 #include "grlib.h"
24 #include "play.h"
25
26 #ifdef HAVE_LIBGEN_H
27 #include <libgen.h>
28 #endif
29
30 #include "i18n.h"
31
32 #ifndef M_PI
33 #define M_PI 3.14159265358979323846
34 #endif
35
36 #define WAITTIME 50000
37 #define WAITTIME1 200000
38 #define WAITTIME2 2000000
39 #define uih_palettechg(uih) \
40 if (!uih->recalculatemode && uih->queue->palettechg != NULL) \
41 uih->recalculatemode = UIH_PALETTEDRAW, uih->display = 1
42 #include "misc-f.h"
43
44 static struct filter *uih_getinstance(const struct filteraction *a);
45 static void uih_destroyinstance(struct filter *f);
46 static int uih_require(struct filter *f, struct requirements *r);
47 static int uih_initialize(struct filter *f, struct initdata *i);
48 static const rgb_t uicolors[] = {
49 {0, 0, 0}, {255, 255, 255}, {255, 65, 0},
50 {64, 64, 64}, {128, 128, 128}, {128 + 64, 128 + 64, 128 + 64}};
51
52 static const rgb_t uibwcolors[] = {{0, 0, 0}, {255, 255, 255},
53 {255, 255, 255}, {255, 255, 255},
54 {255, 255, 255}, {255, 255, 255}};
55
56 static const struct filteraction uih_filter = {"XaoS's user interface layer",
57 "ui",
58 0,
59 uih_getinstance,
60 uih_destroyinstance,
61 NULL,
62 uih_require,
63 uih_initialize,
64 convertupgeneric,
65 convertdowngeneric,
66 NULL};
67
68 static uih_context *uih;
69 static int waitcount, waitcount1, waitcount2;
70
71 const struct filteraction *const uih_filters[MAXFILTERS] = {&edge_filter,
72 &edge2_filter,
73 &threed_filter,
74 &starfield_filter,
75 &stereogram_filter,
76 &interlace_filter,
77 &blur_filter,
78 &emboss_filter,
79 &palette_filter,
80 &antialias_filter,
81 NULL};
82
83 const int uih_nfilters = 10;
84
uih_invalidatepos(uih_context * uih)85 static void uih_invalidatepos(uih_context *uih)
86 {
87 uih->xcenterm = INT_MAX;
88 uih->xcenterm = INT_MAX;
89 }
90
uih_finishpalette(struct uih_context * uih)91 static void uih_finishpalette(struct uih_context *uih)
92 {
93 if (uih->image->palette->flags & UNFINISHED) {
94 if (uih->image->palette->allocfinished != NULL)
95 uih->image->palette->allocfinished(uih->image->palette);
96 uih->image->palette->flags &= ~UNFINISHED;
97 }
98 }
99
uih_getcoord(uih_context * uih,int x,int y,number_t * xr,number_t * yr)100 static void uih_getcoord(uih_context *uih, int x, int y, number_t *xr,
101 number_t *yr)
102 {
103 uih->uifilter->action->convertdown(uih->uifilter, &x, &y);
104 *xr = (((number_t)(uih->fcontext->rs.nc +
105 (x) * ((uih->fcontext->rs.mc - uih->fcontext->rs.nc) /
106 (number_t)uih->zengine->image->width))));
107 *yr = (((number_t)(uih->fcontext->rs.ni +
108 (y) * ((uih->fcontext->rs.mi - uih->fcontext->rs.ni) /
109 (number_t)uih->zengine->image->height))));
110 rotateback(*(uih->fcontext), *xr, *yr);
111 }
112
uih_enablefilter(uih_context * c,int n)113 int uih_enablefilter(uih_context *c, int n)
114 {
115 if (c->filter[n] == NULL) {
116 struct filter *f, *f1;
117 int i, wascycling = 0;
118 if (c->cycling)
119 uih_cycling_off(c), wascycling = 1;
120 f = uih_filters[n]->getinstance(uih_filters[n]);
121 f1 = c->uifilter;
122 if (c->fixedcolor != NULL)
123 f1 = c->fixedcolor;
124 for (i = MAXFILTERS - 1; i > n; i--) {
125 if (c->filter[i])
126 f1 = c->filter[i];
127 }
128 uih_newimage(c);
129 insertfilter(f, f1);
130 if (!initqueue(c->queue)) {
131 c->ddatalost = 1;
132 removefilter(f);
133 f->action->destroyinstance(f);
134 if (!initqueue(c->queue)) {
135 x_fatalerror(
136 "Fatal error. Can not continue - initialization of queue can not be performed eigher with or without filter");
137 }
138 if (wascycling)
139 uih_cycling_on(c);
140 if (!strcmp("palette", uih_filters[n]->shortname)) {
141 uih_updatemenus(c, "palettef");
142 } else {
143 uih_updatemenus(c, uih_filters[n]->shortname);
144 }
145 return 0;
146 } else
147 c->filter[n] = f;
148 if (wascycling)
149 uih_cycling_on(c);
150 if (!strcmp("palette", uih_filters[n]->shortname)) {
151 uih_updatemenus(c, "palettef");
152 } else {
153 uih_updatemenus(c, uih_filters[n]->shortname);
154 }
155 return 1;
156 }
157 return 0;
158 }
159
uih_disablefilter(uih_context * c,int n)160 void uih_disablefilter(uih_context *c, int n)
161 {
162 if (n == c->aliasnum)
163 return;
164 if (c->filter[n] != NULL) {
165 int wascycling = 0;
166 struct filter *f = c->filter[n];
167 if (c->cycling)
168 uih_cycling_off(c), wascycling = 1;
169 uih_newimage(c);
170 removefilter(f);
171 if (!initqueue(c->queue)) {
172 struct filter *f1;
173 int i;
174 c->ddatalost = 1;
175 f1 = c->uifilter;
176 if (c->fixedcolor != NULL)
177 f1 = c->fixedcolor;
178 for (i = MAXFILTERS - 1; i > n; i--) {
179 if (c->filter[i])
180 f1 = c->filter[i];
181 }
182 insertfilter(f, f1);
183 if (!initqueue(c->queue)) {
184 x_fatalerror("Fatal error. Can not continue");
185 }
186 } else
187 f->action->destroyinstance(f), c->filter[n] = NULL;
188 if (wascycling)
189 uih_cycling_on(c);
190 if (!strcmp("palette", uih_filters[n]->shortname)) {
191 uih_updatemenus(c, "palettef");
192 } else {
193 uih_updatemenus(c, uih_filters[n]->shortname);
194 }
195 }
196 }
197
uih_fastrotateenable(uih_context * c)198 int uih_fastrotateenable(uih_context *c)
199 {
200 int wascycling = 0;
201 if (c->juliamode)
202 uih_disablejulia(c);
203 if (!c->fastrotate && !c->juliamode) {
204 if (c->cycling)
205 uih_cycling_off(c), wascycling = 1;
206 c->rotatef = rotate_filter.getinstance(&rotate_filter);
207 if (c->rotatef == NULL)
208 goto end;
209 uih_newimage(c);
210 addfilter(c->rotatef, c->zengine);
211 if (!initqueue(c->queue))
212 goto end2;
213 if (wascycling)
214 uih_cycling_on(c);
215 c->fastrotate = 1;
216 return 1;
217 }
218 return 0;
219 end2:
220 removefilter(c->rotatef);
221 initqueue(c->queue);
222 c->rotatef->action->destroyinstance(c->rotatef);
223 end:
224 if (wascycling)
225 uih_cycling_on(c);
226 return 0;
227 }
228
uih_fastrotatedisable(uih_context * c)229 void uih_fastrotatedisable(uih_context *c)
230 {
231 if (c->fastrotate) {
232 int wascycling = 0;
233 uih_rotatemode(c, ROTATE_NONE);
234 if (c->cycling)
235 uih_cycling_off(c), wascycling = 1;
236 c->fastrotate = 0;
237 removefilter(c->rotatef);
238 initqueue(c->queue);
239 c->rotatef->action->destroyinstance(c->rotatef);
240 uih_newimage(c);
241 if (wascycling)
242 uih_cycling_on(c);
243 }
244 }
245
uih_rotate(struct uih_context * c,int n)246 void uih_rotate(struct uih_context *c, int n)
247 {
248 if (!n)
249 uih_fastrotate(c, 0);
250 else {
251 uih_fastrotate(c, 1);
252 uih_rotatemode(c, n);
253 }
254 }
255
uih_fixedcolordisable(uih_context *)256 static void uih_fixedcolordisable(uih_context * /*c*/)
257 {
258 #ifdef SCONVERTORS
259 if (c->fixedcolor != NULL) {
260 int wascycling = 0;
261 if (c->cycling)
262 uih_cycling_off(c), wascycling = 1;
263 initqueue(c->queue);
264 removefilter(c->fixedcolor);
265 initqueue(c->queue);
266 c->fixedcolor->action->destroyinstance(c->fixedcolor);
267 c->fixedcolor = NULL;
268 uih_newimage(c);
269 if (wascycling)
270 uih_cycling_on(c);
271 }
272 #endif
273 }
274
uih_fixedcolorenable(uih_context *)275 static int uih_fixedcolorenable(uih_context * /*c*/)
276 {
277 #ifdef SCONVERTORS
278 const struct filteraction *fa = NULL;
279 int wascycling = 0;
280 preallocpalette(c->palette);
281 switch (c->image->palette->type) {
282 #ifdef SFIXEDCOLOR
283 case FIXEDCOLOR:
284 fa = &fixedcolor_filter;
285 break;
286 #endif
287 #ifdef SBITMAPS
288 case LBITMAP:
289 case MBITMAP:
290 case LIBITMAP:
291 case MIBITMAP:
292 fa = &bitmap_filter;
293 break;
294 #endif
295 default:
296 x_fatalerror("Unsupported image type. Recompile XaoS");
297 }
298 if (c->fixedcolor != NULL && c->fixedcolor->action != fa)
299 uih_fixedcolordisable(c);
300 if (c->fixedcolor == NULL) {
301 if (c->cycling)
302 uih_cycling_off(c), wascycling = 1;
303 c->fixedcolor = fa->getinstance(fa);
304 if (c->fixedcolor == NULL)
305 goto end;
306 uih_newimage(c);
307 addfilter(c->fixedcolor, c->uifilter->previous);
308 if (!initqueue(c->queue))
309 goto end2;
310 if (wascycling)
311 uih_cycling_on(c);
312 return 1;
313 }
314 return 0;
315 end2:
316 removefilter(c->fixedcolor);
317 c->fixedcolor->action->destroyinstance(c->fixedcolor);
318 c->fixedcolor = NULL;
319 initqueue(c->queue);
320 end:
321 if (wascycling)
322 uih_cycling_on(c);
323 return 0;
324 #else
325 x_fatalerror("Fixed color not supported, please recompile XaoS");
326 return 0;
327 #endif
328 }
329
uih_fastrotate(uih_context * c,int mode)330 int uih_fastrotate(uih_context *c, int mode)
331 {
332 if (mode)
333 return (uih_fastrotateenable(c));
334 uih_fastrotatedisable(c);
335 return 1;
336 }
337
uih_angle(uih_context * c,number_t angle)338 void uih_angle(uih_context *c, number_t angle)
339 {
340 if (angle != c->fcontext->angle) {
341 if (!c->fastrotate) {
342 c->fcontext->version++;
343 uih_newimage(c);
344 }
345 c->fcontext->angle = angle;
346 uih_animate_image(c);
347 }
348 }
349
uih_rotatemode(uih_context * c,int mode)350 void uih_rotatemode(uih_context *c, int mode)
351 {
352 const char *names[] = {"norotate", "mouserotate", "controtate"};
353 if (c->fastrotate) {
354 if (c->rotatemode != mode) {
355 c->rotatemode = mode;
356 if (mode == ROTATE_CONTINUOUS)
357 tl_reset_timer(c->doittimer);
358 uih_updatemenus(c, names[mode]);
359 }
360 }
361 }
362
uih_enablejulia(uih_context * c)363 int uih_enablejulia(uih_context *c)
364 {
365 int wascycling = 0;
366 if (!c->juliamode && c->fcontext->mandelbrot
367 /*&&c->fcontext->currentformula->calculate_julia != NULL */) {
368 struct filter *addf = c->zengine;
369 uih_newimage(c);
370 if (c->fastrotate)
371 uih_fastrotatedisable(c);
372 if (c->cycling)
373 uih_cycling_off(c), wascycling = 1;
374 if (c->fcontext->currentformula->calculate_julia == NULL ||
375 c->fcontext->slowmode)
376 c->julia = zoom_filter.getinstance(&zoom_filter);
377 else
378 c->julia = julia_filter.getinstance(&julia_filter);
379 if (c->julia == NULL)
380 goto end;
381
382 c->subwindow = subwindow_filter.getinstance(&subwindow_filter);
383 if (c->subwindow == NULL)
384 goto end2;
385 if (c->fcontext->currentformula->calculate_julia != NULL &&
386 !c->fcontext->slowmode) {
387 c->smalliter = smalliter_filter.getinstance(&smalliter_filter);
388 if (c->smalliter == NULL)
389 goto end3;
390 } else
391 c->smalliter = NULL;
392 addfilter(c->subwindow, addf);
393 if (c->fcontext->currentformula->calculate_julia != NULL &&
394 !c->fcontext->slowmode) {
395 addfilter(c->smalliter, addf);
396 }
397 addfilter(c->julia, addf);
398 subwindow_setsecond(c->subwindow, addf);
399 if (!initqueue(c->queue))
400 goto end4;
401 if (c->fcontext->currentformula->calculate_julia == NULL ||
402 c->fcontext->slowmode)
403 c->juliamode = 2;
404 else
405 c->juliamode = 1;
406 uih_updatemenus(c, "fastjulia");
407 return 1;
408 }
409 uih_updatemenus(c, "fastjulia");
410 return 0;
411 end4:;
412 removefilter(c->subwindow);
413 removefilter(c->julia);
414 if (c->smalliter != NULL)
415 removefilter(c->smalliter);
416 initqueue(c->queue);
417 end3:;
418 c->smalliter->action->destroyinstance(c->smalliter);
419 end2:;
420 c->subwindow->action->destroyinstance(c->subwindow);
421 end:;
422 c->julia->action->destroyinstance(c->julia);
423 if (wascycling)
424 uih_cycling_on(c);
425 uih_updatemenus(c, "fastjulia");
426 return 0;
427 }
428
uih_disablejulia(uih_context * c)429 void uih_disablejulia(uih_context *c)
430 {
431 int wascycling = 0;
432 if (c->juliamode) {
433 uih_newimage(c);
434 c->fcontext->version++;
435 if (c->cycling)
436 uih_cycling_off(c), wascycling = 1;
437 removefilter(c->subwindow);
438 removefilter(c->julia);
439 if (c->smalliter != NULL)
440 removefilter(c->smalliter);
441 initqueue(c->queue);
442 if (c->smalliter != NULL)
443 c->smalliter->action->destroyinstance(c->smalliter);
444 c->subwindow->action->destroyinstance(c->subwindow);
445 c->julia->action->destroyinstance(c->julia);
446 if (wascycling)
447 uih_cycling_on(c);
448 c->juliamode = 0;
449 uih_updatemenus(c, "fastjulia");
450 }
451 }
452
uih_setjuliamode(uih_context * c,int mode)453 int uih_setjuliamode(uih_context *c, int mode)
454 {
455 if (mode)
456 return uih_enablejulia(c);
457 uih_disablejulia(c);
458 return 1;
459 }
460
uih_rotationspeed(uih_context * c,number_t speed)461 void uih_rotationspeed(uih_context *c, number_t speed)
462 {
463 c->rotationspeed = speed;
464 }
465
uih_cyclinghandler(void * userdata,int n)466 static void uih_cyclinghandler(void *userdata, int n)
467 {
468 struct uih_context *uih = (struct uih_context *)userdata;
469 int direct;
470 if (uih->zengine->fractalc->palette != NULL &&
471 uih->zengine->fractalc->palette->cyclecolors == NULL)
472 return;
473 direct = uih->direction * uih->cyclingdirection * n;
474 if (direct > 0)
475 direct %= uih->zengine->fractalc->palette->size - 1;
476 else
477 direct = -((-direct) % (uih->zengine->fractalc->palette->size - 1));
478 if (direct) {
479 uih->paletteshift += direct;
480 while (uih->paletteshift < 0)
481 uih->paletteshift += uih->zengine->fractalc->palette->size - 1;
482 uih->paletteshift =
483 uih->paletteshift % (uih->zengine->fractalc->palette->size - 1);
484 uih->zengine->fractalc->palette->cyclecolors(
485 uih->zengine->fractalc->palette, direct);
486 if (uih->flags & UPDATE_AFTER_PALETTE &&
487 (!uih->play || !uih->nonfractalscreen))
488 uih->display = 1;
489 uih_palettechg(uih);
490 }
491 }
492
uih_cycling_off(struct uih_context * c)493 void uih_cycling_off(struct uih_context *c)
494 {
495 if (c->cycling) {
496 tl_free_timer(c->cyclingtimer);
497 c->cycling = 0;
498 uih_updatemenus(c, "cycling");
499 uih_updatemenus(c, "rcycling");
500 }
501 }
502
uih_display(struct uih_context * c)503 void uih_display(struct uih_context *c)
504 {
505 c->display = 1;
506 c->nonfractalscreen = 0;
507 if (c->clearscreen)
508 c->clearscreen = 0;
509 c->displaytext = 0;
510 c->nletters = 0;
511 c->display = 1;
512 if (c->text[0] != NULL)
513 free(c->text[0]), c->text[0] = NULL;
514 if (c->text[1] != NULL)
515 free(c->text[1]), c->text[1] = NULL;
516 if (c->text[2] != NULL)
517 free(c->text[2]), c->text[2] = NULL;
518 if (c->play)
519 uih_clear_lines(c);
520 }
521
uih_cycling_stop(struct uih_context * c)522 void uih_cycling_stop(struct uih_context *c)
523 {
524 if (c->cycling && !c->stopped) {
525 tl_remove_timer(c->cyclingtimer);
526 c->stopped = 1;
527 }
528 }
529
uih_cycling_continue(struct uih_context * c)530 void uih_cycling_continue(struct uih_context *c)
531 {
532 if (c->cycling && c->stopped) {
533 c->stopped = 0;
534 tl_add_timer(syncgroup, c->cyclingtimer);
535 }
536 }
537
uih_loadfile(struct uih_context * c,xio_constpath d)538 void uih_loadfile(struct uih_context *c, xio_constpath d)
539 {
540 int los = strlen(d);
541 char ext[4];
542 if(los < 3)
543 return;
544 memcpy(ext, &d[los-3], 3);
545 if(strcmp(ext, "png") == 0) {
546 uih_loadpngfile(c, d);
547 return;
548 }
549
550 xio_file f;
551 f = xio_ropen(d);
552 if (f == NULL) {
553 uih_error(c, strerror(errno));
554 return;
555 }
556 uih_load(c, f, d);
557 return;
558 }
559
uih_loadstr(struct uih_context * c,const char * data)560 void uih_loadstr(struct uih_context *c, const char *data)
561 {
562 xio_file f;
563 f = xio_strropen(data);
564 uih_load(c, f, "");
565 return;
566 }
567
uih_playstr(struct uih_context * c,const char * data)568 void uih_playstr(struct uih_context *c, const char *data)
569 {
570 xio_file f;
571 f = xio_strropen(mystrdup(data));
572 uih_replayenable(c, f, "", 1);
573 return;
574 }
575
uih_recalculate(struct uih_context * c)576 void uih_recalculate(struct uih_context *c)
577 {
578 c->fcontext->version++;
579 uih_newimage(c);
580 }
581
uih_playfile(struct uih_context * c,xio_constpath d)582 void uih_playfile(struct uih_context *c, xio_constpath d)
583 {
584 xio_file f;
585 if (c->play)
586 uih_replaydisable(c);
587 f = xio_ropen(d);
588 if (f == NULL) {
589 uih_error(c, strerror(errno));
590 return;
591 }
592 uih_replayenable(c, f, d, 1);
593 return;
594 }
595
uih_playtutorial(struct uih_context * c,const char * name)596 void uih_playtutorial(struct uih_context *c, const char *name)
597 {
598 xio_pathdata tmp;
599 xio_file f = XIO_FAILED;
600
601 f = xio_gettutorial(name, tmp);
602 if (f == NULL) {
603 uih_error(c, TR("Error", "Tutorial files not found. Reinstall XaoS"));
604 return;
605 }
606 uih_replayenable(c, f, tmp, 1);
607 if (c->passfunc != NULL) {
608 c->passfunc(c, 1, TR("Message", "Preparing first image"), 0);
609 }
610 }
611
uih_loadexample(struct uih_context * c)612 void uih_loadexample(struct uih_context *c)
613 {
614 xio_pathdata name;
615 xio_file f = xio_getrandomexample(name);
616 c->errstring = NULL;
617 if (f == NULL) {
618 uih_error(c, TR("Error", "Could not open examples"));
619 return;
620 }
621 uih_load(c, f, name);
622 if (c->errstring == NULL) {
623 char s[256];
624 #ifdef HAVE_LIBGEN_H
625 sprintf(s, TR("Message", "File %s loaded."), basename(name));
626 #else
627 sprintf(s, TR("Message", "File %s loaded."), name);
628 #endif
629 uih_message(c, s);
630 }
631 }
632
uih_loadpngfile(struct uih_context * c,xio_constpath d)633 void uih_loadpngfile(struct uih_context *c, xio_constpath d)
634 {
635 xio_file f;
636 f = xio_ropen(d);
637 if (f == NULL) {
638 uih_error(c, strerror(errno));
639 return;
640 }
641 const char* xpf_chunk = readpng(d);
642 if(xpf_chunk == NULL) {
643 uih_error(c, TR("Error", "Could not open image"));
644 return;
645 }
646 xio_file xpf_data = xio_strropen(xpf_chunk);
647 uih_load(c, xpf_data, d);
648 if(c->errstring == NULL) {
649 char s[256];
650 sprintf(s, TR("Message", "File %s loaded."), d);
651 uih_message(c, s);
652 }
653 return;
654 }
655
uih_savepngfile(struct uih_context * c,xio_constpath d)656 void uih_savepngfile(struct uih_context *c, xio_constpath d)
657 {
658 const char *s;
659 if (c->passfunc != NULL) {
660 c->passfunc(c, 1, TR("Message", "Saving image..."), 0);
661 }
662 if (c->recalculatemode) {
663 uih_newimage(c);
664 uih_clearwindows(c);
665 uih_do_fractal(c);
666 }
667 if (c->interrupt) {
668 uih_message(c, TR("Message", "Save interrupted"));
669 return;
670 }
671 c->errstring = NULL;
672 xio_file xpf_data = xio_strwopen();
673 uih_save_position(c, xpf_data, UIH_SAVEPOS);
674 s = uih_save(c, d, xpf_data);
675 if (s != NULL)
676 uih_error(c, s);
677 if (c->errstring == NULL) {
678 char s[256];
679 sprintf(s, TR("Message", "File %s saved."), d);
680 uih_message(c, s);
681 }
682 }
683
uih_saveposfile(struct uih_context * c,xio_constpath d)684 void uih_saveposfile(struct uih_context *c, xio_constpath d)
685 {
686 xio_file f;
687 c->errstring = NULL;
688 f = xio_wopen(d);
689 if (f == XIO_FAILED) {
690 uih_error(c, TR("Message", "Can not open file"));
691 return;
692 }
693 uih_save_position(c, f, UIH_SAVEPOS);
694 if (c->errstring == NULL) {
695 char s[256];
696 sprintf(s, TR("Message", "File %s saved."), d);
697 uih_message(c, s);
698 }
699 }
700
uih_savepostostr(struct uih_context * c)701 char *uih_savepostostr(struct uih_context *c)
702 {
703 xio_file f;
704 c->errstring = NULL;
705 f = xio_strwopen();
706 uih_save_position(c, f, UIH_SAVEPOS);
707 return (xio_getstring(f));
708 }
709
uih_saveundo(struct uih_context * c)710 void uih_saveundo(struct uih_context *c)
711 {
712 xio_file f;
713 if (c->play)
714 return;
715 c->errstring = NULL;
716 if (c->undo.undos[c->undo.last])
717 free(c->undo.undos[c->undo.last]);
718 f = xio_strwopen();
719 uih_save_position(c, f, UIH_SAVEPOS);
720 c->undo.undos[c->undo.last] = xio_getstring(f);
721 c->undo.last = (c->undo.last + 1) % UNDOLEVEL;
722 }
723
uih_undo(struct uih_context * c)724 void uih_undo(struct uih_context *c)
725 {
726 xio_file f;
727 int pos = c->undo.last - 2;
728 if (pos < 0)
729 pos = UNDOLEVEL + pos;
730 if (c->undo.undos[pos]) {
731 f = xio_strropen(c->undo.undos[pos]);
732 c->undo.undos[pos] = NULL;
733 c->undo.last = pos;
734 uih_load(c, f, "");
735 }
736 }
737
uih_redo(struct uih_context * c)738 void uih_redo(struct uih_context *c)
739 {
740 xio_file f;
741 int pos = c->undo.last;
742 if (c->undo.undos[pos]) {
743 f = xio_strropen(c->undo.undos[pos]);
744 c->undo.undos[pos] = NULL;
745 c->undo.last = pos;
746 uih_load(c, f, "");
747 }
748 }
749
750 extern xio_pathdata configfile;
uih_savecfg(struct uih_context * c)751 void uih_savecfg(struct uih_context *c)
752 {
753 xio_file f;
754 c->errstring = NULL;
755 f = xio_wopen(configfile);
756 if (f == XIO_FAILED) {
757 uih_message(c, (char *)xio_errorstring());
758 return;
759 }
760 uih_save_position(c, f, UIH_SAVEALL);
761 if (c->errstring == NULL) {
762 char s[256];
763 sprintf(s, TR("Message", "File %s saved."), configfile);
764 uih_message(c, s);
765 }
766 }
767
uih_saveanimfile(struct uih_context * c,xio_constpath d)768 void uih_saveanimfile(struct uih_context *c, xio_constpath d)
769 {
770 xio_file f;
771 c->errstring = NULL;
772 if (c->save) {
773 uih_save_disable(c);
774 uih_updatemenus(c, "record");
775 return;
776 }
777 f = xio_wopen(d);
778 if (f == XIO_FAILED) {
779 uih_message(c, (char *)xio_errorstring());
780 return;
781 }
782 uih_save_enable(c, f, UIH_SAVEANIMATION);
783 if (c->errstring == NULL) {
784 char s[256];
785 sprintf(s, TR("Message", "Recording to file %s enabled."), d);
786 uih_message(c, s);
787 }
788 uih_updatemenus(c, "record");
789 }
790
uih_save(struct uih_context * c,xio_constpath filename,xio_file xpf_data)791 const char *uih_save(struct uih_context *c, xio_constpath filename, xio_file xpf_data)
792 {
793 const char *r;
794 uih_cycling_stop(c);
795 uih_stoptimers(c);
796 uih_clearwindows(c);
797 r = writepng(filename, c->queue->saveimage, xpf_data);
798 uih_cycling_continue(c);
799 uih_resumetimers(c);
800 return (r);
801 }
802
uih_setcycling(struct uih_context * c,int speed)803 void uih_setcycling(struct uih_context *c, int speed)
804 {
805 c->cyclingspeed = speed;
806 if (c->cyclingspeed < 0)
807 c->direction = -1;
808 else
809 c->direction = 1;
810 if (c->cycling) {
811 if (c->cyclingspeed)
812 tl_set_interval(c->cyclingtimer,
813 1000000 / c->cyclingspeed * c->direction);
814 else
815 tl_set_interval(c->cyclingtimer, 1000000 * 100);
816 }
817 }
818
uih_cycling_on(struct uih_context * c)819 int uih_cycling_on(struct uih_context *c)
820 {
821 if (c->zengine->fractalc->palette != NULL &&
822 c->zengine->fractalc->palette->cyclecolors != NULL) {
823 c->cycling = 1;
824 tl_update_time();
825 c->cyclingtimer = tl_create_timer();
826 uih_emulatetimers(c);
827 uih_setcycling(c, c->cyclingspeed);
828 tl_set_multihandler(c->cyclingtimer, uih_cyclinghandler, c);
829 tl_add_timer(syncgroup, c->cyclingtimer);
830 } else {
831 uih_updatemenus(c, "cycling");
832 uih_updatemenus(c, "rcycling");
833 return 0;
834 }
835 uih_updatemenus(c, "cycling");
836 uih_updatemenus(c, "rcycling");
837 return 1;
838 }
839
uih_cycling(struct uih_context * uih,int mode)840 int uih_cycling(struct uih_context *uih, int mode)
841 {
842 if (mode)
843 return (uih_cycling_on(uih));
844 uih_cycling_off(uih);
845 return 1;
846 }
847
uih_waitfunc(struct filter * f)848 static void uih_waitfunc(struct filter *f)
849 {
850 int l;
851 tl_process_group(syncgroup, NULL);
852 l = tl_lookup_timer(uih->calculatetimer);
853 if (uih->interrupt)
854 f->interrupt = 1, uih->endtime = l;
855 if (uih->interruptiblemode) {
856 if (f->incalculation && !uih->starttime)
857 uih->starttime = l;
858 else if (uih->starttime && !f->incalculation && !uih->endtime)
859 uih->endtime = l;
860 if ((uih->maxtime && l > uih->maxtime && f->readyforinterrupt) ||
861 uih->interrupt)
862 f->interrupt = 1, uih->endtime = l;
863 }
864 if ((l) > (waitcount + 1) * WAITTIME) {
865 int display = 0;
866 if (!uih->interruptiblemode && l > (waitcount1 + 1) * WAITTIME1) {
867 display = 1;
868 waitcount1 = l / WAITTIME1;
869 }
870 if (f->image == uih->image && !uih->interruptiblemode &&
871 l > (waitcount2 + 1) * WAITTIME2) {
872 if (!uih->play)
873 uih->display = 1, uih_finishpalette(uih), display = 1;
874 waitcount2 = l / WAITTIME2;
875 }
876 if (uih->passfunc != NULL) {
877 f->interrupt |= uih->passfunc(
878 uih, display, f->pass,
879 (float)(f->max ? f->pos * 100.0 / f->max : 100.0));
880 uih->display = 0;
881 }
882 waitcount = l / WAITTIME;
883 }
884 uih_clearwindows(uih);
885 }
886
uih_do_fractal(uih_context * c)887 void uih_do_fractal(uih_context *c)
888 {
889 int flags;
890 int time;
891
892 c->interrupt = 0;
893 c->display = 0;
894 uih = c;
895 if (c->juliamode && !c->fcontext->mandelbrot) {
896 uih_disablejulia(c);
897 }
898 if ((c->juliamode == 1 &&
899 (c->fcontext->currentformula->calculate_julia == NULL ||
900 c->fcontext->slowmode)) ||
901 (c->juliamode == 2 &&
902 c->fcontext->currentformula->calculate_julia != NULL &&
903 !c->fcontext->slowmode)) {
904 uih_disablejulia(c);
905 uih_enablejulia(c);
906 c->fcontext->version++;
907 }
908
909 tl_update_time();
910 if (c->recalculatemode < c->fastmode && c->emulator == NULL &&
911 !c->fixedstep)
912 c->interruptiblemode = 1;
913 else
914 c->interruptiblemode = 0;
915 if (!c->interruptiblemode && c->recalculatemode > UIH_ANIMATION) {
916 if (c->longwait != NULL)
917 c->longwait(c);
918 uih_stoptimers(c);
919 }
920
921 tl_update_time();
922 tl_reset_timer(c->calculatetimer);
923 c->starttime = 0;
924 c->endtime = 0;
925 waitcount = tl_lookup_timer(c->calculatetimer) / WAITTIME + 2;
926 waitcount1 = tl_lookup_timer(c->calculatetimer) / WAITTIME1 + 1;
927 waitcount2 = tl_lookup_timer(c->calculatetimer) / WAITTIME2 + 1;
928 c->incalculation = 1;
929
930 if (!(c->flags & ROTATE_INSIDE_CALCULATION))
931 uih_cycling_stop(c);
932
933 time = tl_lookup_timer(c->doittimer);
934 if (c->rotatemode == ROTATE_CONTINUOUS) {
935 c->fcontext->angle += c->rotationspeed * time / 1000000.0;
936 }
937
938 tl_reset_timer(c->doittimer);
939 c->indofractal = 1;
940 if (c->recalculatemode < UIH_PALETTEDRAW) {
941 if (c->queue->palettechg != NULL)
942 flags = c->queue->palettechg->action->doit(c->queue->palettechg,
943 PALETTEONLY, 0);
944 else
945 flags = CHANGED;
946 } else
947 flags = c->uifilter->previous->action->doit(
948 c->uifilter->previous, c->interruptiblemode ? INTERRUPTIBLE : 0,
949 time);
950 c->indofractal = 0;
951
952 if (!(c->flags & ROTATE_INSIDE_CALCULATION))
953 uih_cycling_continue(c);
954
955 c->dirty = 0;
956 if (c->inanimation)
957 c->inanimation--;
958 c->ddatalost = 0;
959 c->recalculatemode = 0;
960
961 if (flags & ANIMATION)
962 c->fastanimation = 1;
963 else
964 c->fastanimation = 0;
965 if (c->emulator)
966 c->inanimation = 1;
967 if (flags & (ANIMATION | INCOMPLETE) ||
968 (c->rotatemode == ROTATE_CONTINUOUS)) {
969 tl_resume_timer(c->doittimer);
970 c->incomplete = 1;
971 c->inanimation = 2;
972 if (flags & INCOMPLETE)
973 c->recalculatemode = UIH_ANIMATION;
974 else
975 c->recalculatemode = UIH_FILTERANIMATION;
976 c->display = 1;
977 } else {
978 tl_stop_timer(c->doittimer);
979 c->incomplete = 0;
980 }
981 if ((flags & CHANGED) && (!c->play || !c->nonfractalscreen)) {
982 c->display = 1;
983 if (flags & INEXACT)
984 c->dirty = 1;
985 } else
986 c->incalculation = 0;
987 uih_callcomplette(c);
988 if (c->autopilot)
989 c->inanimation = 1;
990 }
991
uih_prepare_image(uih_context * c)992 void uih_prepare_image(uih_context *c)
993 {
994 if (c->play)
995 uih_update_lines(c);
996 if (c->display) {
997 uih_clearwindows(c);
998 xprepareimage(c->image);
999 if (uih_needrecalculate(c))
1000 uih_do_fractal(c);
1001 }
1002 }
1003
uih_callcomplette(uih_context * c)1004 void uih_callcomplette(uih_context *c)
1005 {
1006 if (!c->incomplete && !c->display && !c->recalculatemode &&
1007 !c->inanimation && c->complettehandler != NULL) {
1008 c->complettehandler(c->handlerdata);
1009 }
1010 }
1011
uih_setcomplettehandler(uih_context * c,void (h)(void *),void * d)1012 void uih_setcomplettehandler(uih_context *c, void(h)(void *), void *d)
1013 {
1014 c->complettehandler = h;
1015 c->handlerdata = d;
1016 }
1017
uih_letterspersec(uih_context * c,int n)1018 void uih_letterspersec(uih_context *c, int n)
1019 {
1020 if (n < 1)
1021 n = 1;
1022 c->letterspersec = n;
1023 }
1024
uih_displayed(uih_context * c)1025 double uih_displayed(uih_context *c)
1026 {
1027 int drawingtime;
1028 uih_finishpalette(c);
1029 if (c->indofractal)
1030 return 0; /*image is currently calculating */
1031 if (c->recalculatemode)
1032 c->display = 1;
1033 else
1034 c->display = 0;
1035 tl_update_time();
1036 uih_resumetimers(c);
1037 c->nonfractalscreen = 0;
1038 c->nletters = 0;
1039 if (c->incalculation) {
1040 c->incalculation = 0;
1041 drawingtime = tl_lookup_timer(c->calculatetimer);
1042 if (c->emulator)
1043 drawingtime = 0;
1044 if (c->lasttime == -1 || (drawingtime && c->lasttime &&
1045 (drawingtime / c->lasttime < 0.2 ||
1046 drawingtime / c->lasttime > 4)))
1047 c->lasttime = drawingtime;
1048 c->lasttime = (c->lasttime * 30 + drawingtime) / 31;
1049 c->lastspeed = c->lasttime ? 1000000.0 / c->lasttime : 100.0;
1050 if (c->interruptiblemode) {
1051 int i;
1052 int time1, time;
1053 time1 = drawingtime;
1054 time1 -= c->endtime;
1055 time = (drawingtime - c->endtime) + c->starttime;
1056 if (c->times[0][0] == -1) {
1057 for (i = 0; i < AVRGSIZE; i++)
1058 c->times[0][i] = time, c->times[1][i] = time1;
1059 c->count[0] = time * AVRGSIZE, c->count[1] = time1 * AVRGSIZE;
1060 }
1061 c->timespos = (c->timespos + 1) % AVRGSIZE;
1062 c->count[0] += time - c->times[0][c->timespos];
1063 c->count[1] += time1 - c->times[1][c->timespos];
1064 c->times[0][c->timespos] = time;
1065 c->times[1][c->timespos] = time1;
1066 c->maxtime = (c->count[0] * 5) / AVRGSIZE;
1067 if (c->step || c->pressed ||
1068 (c->play &&
1069 (c->playc->morph || c->playc->morphangle ||
1070 c->playc->morphjulia || c->playc->lines.morphing)) ||
1071 (c->rotatemode == ROTATE_CONTINUOUS) || c->fastanimation) {
1072 if (c->maxtime > 1000000 / 25)
1073 c->maxtime = c->count[0] * 3 / AVRGSIZE;
1074 if (c->maxtime > 1000000 / 15)
1075 c->maxtime = 1000000 / 15;
1076 } else {
1077 c->maxtime = 1000000 / 3;
1078 }
1079 if (c->maxtime < 1000000 / 30)
1080 c->maxtime = 1000000 / 30;
1081 c->maxtime -= c->count[1] / AVRGSIZE;
1082 if (c->maxtime < c->starttime + 10000)
1083 c->maxtime = c->starttime + 10000;
1084 }
1085 }
1086 uih_callcomplette(c);
1087 return (c->lastspeed);
1088 }
1089
uih_text(uih_context * c,const char * text)1090 void uih_text(uih_context *c, const char *text)
1091 {
1092 int i, l;
1093 c->display = 1;
1094 if (c->text[c->ytextpos])
1095 free(c->text[c->ytextpos]);
1096 c->textpos[c->ytextpos] = c->xtextpos;
1097 c->textcolor[c->ytextpos] = c->color;
1098 c->displaytext |= 1 << c->ytextpos;
1099 c->text[c->ytextpos] = mystrdup(text);
1100 l = (int)strlen(text);
1101 c->todisplayletters = 0;
1102 for (i = 0; i < l; i++) {
1103 if (!isspace(text[i]) && !ispunct(text[i]))
1104 c->todisplayletters++;
1105 if (text[i] == '-')
1106 c->todisplayletters += 3;
1107 if (text[i] == '.')
1108 c->todisplayletters += 2;
1109 }
1110 c->step = 0;
1111 }
1112
uih_clearscreen(uih_context * c)1113 void uih_clearscreen(uih_context *c)
1114 {
1115 c->clearscreen = 1;
1116 if (c->save)
1117 c->savec->clearscreen = 1;
1118 if (c->displaytext)
1119 c->displaytext = 0;
1120 if (c->text[0] != NULL)
1121 free(c->text[0]), c->text[0] = NULL;
1122 if (c->text[1] != NULL)
1123 free(c->text[1]), c->text[1] = NULL;
1124 if (c->text[2] != NULL)
1125 free(c->text[2]), c->text[2] = NULL;
1126 c->nletters = 0;
1127 c->display = 1;
1128 if (c->play)
1129 uih_clear_lines(c);
1130 }
1131
uih_settextpos(uih_context * c,int x,int y)1132 void uih_settextpos(uih_context *c, int x, int y)
1133 {
1134 const char *names1[] = {
1135 "ytextposup",
1136 "ytextposmiddle",
1137 "ytextposbottom",
1138 };
1139 const char *names2[] = {
1140 "xtextposleft",
1141 "xtextposcenter",
1142 "xtextposright",
1143 };
1144 c->xtextpos = x;
1145 c->ytextpos = y;
1146 uih_updatemenus(c, names1[y]);
1147 uih_updatemenus(c, names2[x]);
1148 }
1149
1150 /*timing routines */
1151
uih_tbreak(uih_context * c)1152 void uih_tbreak(uih_context *c) { c->tbreak = 1; }
1153
uih_emulatetimers(uih_context * c)1154 void uih_emulatetimers(uih_context *c)
1155 {
1156 if (c->emulator == NULL)
1157 return;
1158 tl_emulate_timer(c->maintimer, c->emulator);
1159 tl_emulate_timer(c->doittimer, c->emulator);
1160 if (c->autopilot)
1161 tl_emulate_timer(c->autopilottimer, c->emulator);
1162 if (c->cycling) {
1163 tl_emulate_timer(c->cyclingtimer, c->emulator);
1164 }
1165 if (c->play) {
1166 tl_emulate_timer(c->playc->timer, c->emulator);
1167 }
1168 if (c->save) {
1169 tl_emulate_timer(c->savec->timer, c->emulator);
1170 tl_emulate_timer(c->savec->synctimer, c->emulator);
1171 }
1172 }
1173
uih_unemulatetimers(uih_context * c)1174 static void uih_unemulatetimers(uih_context *c)
1175 {
1176 tl_unemulate_timer(c->maintimer);
1177 tl_unemulate_timer(c->doittimer);
1178 if (c->autopilot)
1179 tl_unemulate_timer(c->autopilottimer);
1180 if (c->cycling)
1181 tl_unemulate_timer(c->cyclingtimer);
1182 if (c->play) {
1183 tl_unemulate_timer(c->playc->timer);
1184 }
1185 if (c->save) {
1186 tl_unemulate_timer(c->savec->timer);
1187 tl_unemulate_timer(c->savec->synctimer);
1188 }
1189 }
1190
uih_constantframetime(uih_context * c,int time)1191 void uih_constantframetime(uih_context *c, int time)
1192 {
1193 if (c->emulator == NULL)
1194 c->emulator = tl_create_emulator();
1195 c->emulatedframetime = time;
1196 uih_emulatetimers(c);
1197 }
1198
uih_noconstantframetime(uih_context * c)1199 void uih_noconstantframetime(uih_context *c)
1200 {
1201 if (c->emulator == NULL)
1202 return;
1203 uih_unemulatetimers(c);
1204 tl_free_emulator(c->emulator);
1205 c->emulator = NULL;
1206 }
1207
uih_stoptimers(uih_context * c)1208 void uih_stoptimers(uih_context *c)
1209 {
1210 if (!c->stoppedtimers) {
1211 c->stoppedtimers = 1;
1212 c->display = 1;
1213 tl_stop_timer(c->maintimer);
1214 tl_stop_timer(c->doittimer);
1215 if (c->autopilot)
1216 tl_stop_timer(c->autopilottimer);
1217 if (c->play) {
1218 tl_stop_timer(c->playc->timer);
1219 if (c->cycling)
1220 tl_stop_timer(c->cyclingtimer);
1221 }
1222 if (c->save) {
1223 tl_stop_timer(c->savec->timer);
1224 tl_stop_timer(c->savec->synctimer);
1225 if (c->cycling)
1226 tl_stop_timer(c->cyclingtimer);
1227 }
1228 }
1229 }
1230
uih_slowdowntimers(uih_context * c,int time)1231 void uih_slowdowntimers(uih_context *c, int time)
1232 {
1233 tl_slowdown_timer(c->maintimer, time);
1234 if (c->autopilot)
1235 tl_slowdown_timer(c->autopilottimer, time);
1236 if (c->play) {
1237 tl_slowdown_timer(c->playc->timer, time);
1238 if (c->cycling)
1239 tl_slowdown_timer(c->cyclingtimer, time);
1240 }
1241 if (c->save) {
1242 tl_slowdown_timer(c->savec->timer, time);
1243 tl_slowdown_timer(c->savec->synctimer, time);
1244 if (c->cycling)
1245 tl_slowdown_timer(c->cyclingtimer, time);
1246 }
1247 }
1248
uih_resumetimers(uih_context * c)1249 void uih_resumetimers(uih_context *c)
1250 {
1251 if (c->stoppedtimers) {
1252 c->stoppedtimers = 0;
1253 tl_resume_timer(c->maintimer);
1254 if (c->cycling)
1255 tl_resume_timer(c->cyclingtimer);
1256 if (c->autopilot)
1257 tl_resume_timer(c->autopilottimer);
1258 if (c->play) {
1259 tl_resume_timer(c->playc->timer);
1260 }
1261 if (c->save) {
1262 tl_resume_timer(c->savec->timer);
1263 tl_resume_timer(c->savec->synctimer);
1264 }
1265 }
1266 }
1267
1268 /*autopilot implementation */
1269
uih_changed(void)1270 static void uih_changed(void) { uih_newimage(uih); }
1271
uih_autopilothandler(void * uih1,int n)1272 static void uih_autopilothandler(void *uih1, int n)
1273 {
1274 uih = (uih_context *)uih1;
1275 do_autopilot(uih, &uih->autopilotx, &uih->autopiloty,
1276 &uih->autopilotbuttons, uih_changed, n);
1277 }
1278
uih_zoom(uih_context * uih)1279 static inline void uih_zoom(uih_context *uih)
1280 {
1281 uih->step += uih->speedup * 2 * uih->mul;
1282 if (uih->step > uih->maxstep)
1283 uih->step = uih->maxstep;
1284 else if (uih->step < -uih->maxstep)
1285 uih->step = -uih->maxstep;
1286 }
1287
uih_unzoom(uih_context * uih)1288 static inline void uih_unzoom(uih_context *uih)
1289 {
1290 uih->step -= uih->speedup * 2 * uih->mul;
1291 if (uih->step > uih->maxstep)
1292 uih->step = uih->maxstep;
1293 else if (uih->step < -uih->maxstep)
1294 uih->step = -uih->maxstep;
1295 }
1296
uih_slowdown(uih_context * uih)1297 static inline void uih_slowdown(uih_context *uih)
1298 {
1299 if (uih->step > 0) {
1300 if (uih->step < uih->speedup * uih->mul)
1301 uih->step = 0;
1302 else
1303 uih->step -= uih->speedup * uih->mul;
1304 } else if (uih->step < 0) {
1305 if (uih->step > -uih->speedup * uih->mul)
1306 uih->step = 0;
1307 else
1308 uih->step += uih->speedup * uih->mul;
1309 }
1310 }
1311
uih_zoomupdate(uih_context * uih)1312 static inline void uih_zoomupdate(uih_context *uih)
1313 {
1314 number_t x;
1315 number_t y;
1316 number_t mmul = pow((double)(1 - uih->step), (double)uih->mul);
1317 number_t mc = uih->fcontext->s.cr - uih->fcontext->s.rr / 2;
1318 number_t nc = uih->fcontext->s.cr + uih->fcontext->s.rr / 2;
1319 number_t mi = uih->fcontext->s.ci - uih->fcontext->s.ri / 2;
1320 number_t ni = uih->fcontext->s.ci + uih->fcontext->s.ri / 2;
1321 x = uih->xcenter, y = uih->ycenter;
1322 mc = x + (mc - x) * (mmul);
1323 nc = x + (nc - x) * (mmul);
1324 mi = y + (mi - y) * (mmul);
1325 ni = y + (ni - y) * (mmul);
1326 uih->fcontext->s.rr = nc - mc;
1327 uih->fcontext->s.ri = ni - mi;
1328 uih->fcontext->s.cr = (nc + mc) / 2;
1329 uih->fcontext->s.ci = (ni + mi) / 2;
1330 uih_animate_image(uih);
1331 }
1332
1333 /*main uih loop */
1334
uih_update(uih_context * c,int mousex,int mousey,int mousebuttons)1335 int uih_update(uih_context *c, int mousex, int mousey, int mousebuttons)
1336 {
1337 int inmovement = 0;
1338 int slowdown = 1;
1339 int time;
1340 uih = c;
1341
1342 if (!mousebuttons && uih->lastbuttons)
1343 uih_saveundo(c);
1344 uih->lastbuttons = mousebuttons;
1345 if (c->incalculation)
1346 return 0;
1347 if (c->emulator != NULL)
1348 tl_elpased(c->emulator, c->emulatedframetime);
1349
1350 if (mousebuttons == (BUTTON1 | BUTTON3))
1351 mousebuttons = BUTTON2;
1352 tl_process_group(syncgroup, NULL); /*First we need to update timing */
1353 tl_update_time();
1354 time = tl_lookup_timer(c->maintimer);
1355 if (c->autopilot) { /*now handle autopilot */
1356 tl_process_group(c->autopilotgroup, NULL);
1357 }
1358 if (!c->inanimation)
1359 time = 0;
1360 if (time > 2000000) {
1361 uih_slowdowntimers(uih, time - 2000000);
1362 time = 2000000;
1363 }
1364 if (c->inanimation)
1365 c->inanimation--;
1366 tl_reset_timer(c->maintimer);
1367 c->mul = (double)time / FRAMETIME;
1368 if (c->fixedstep)
1369 c->mul = 0.3;
1370 if (c->tbreak)
1371 c->mul = 1, c->tbreak--;
1372 if (c->mul == 0)
1373 c->mul = 0.00000001;
1374 if (c->play) {
1375 uih_playupdate(c);
1376 if (!c->play) {
1377 c->inanimation = 2;
1378 return 1;
1379 }
1380 if (c->playc->lines.morphing) /*inmovement=1, c->display=1; */
1381 uih_update_lines(c);
1382 if (c->step)
1383 uih_zoomupdate(c), inmovement = 1;
1384 switch (c->zoomactive) {
1385 case 1:
1386 uih_zoom(c), inmovement = 1;
1387 break;
1388 case -1:
1389 uih_unzoom(c), inmovement = 1;
1390 break;
1391 default:
1392 uih_slowdown(c);
1393 }
1394 if (c->playc->morph) {
1395 int timer = tl_lookup_timer(c->playc->timer) - c->playc->starttime;
1396 number_t mmul = /*(tl_lookup_timer (c->playc->timer) -
1397 c->playc->starttime) / (number_t)
1398 (c->playc->frametime - c->playc->starttime); */
1399 MORPHVALUE(timer, c->playc->frametime - c->playc->starttime,
1400 c->playc->morphtimes[0], c->playc->morphtimes[1]);
1401 number_t srr, drr;
1402 number_t mmul1;
1403 if (c->playc->source.rr * c->fcontext->windowwidth >
1404 c->playc->source.ri * c->fcontext->windowheight)
1405 srr = c->playc->source.rr;
1406 else
1407 srr = c->playc->source.ri;
1408 if (c->playc->destination.rr * c->fcontext->windowwidth >
1409 c->playc->destination.ri * c->fcontext->windowheight)
1410 drr = c->playc->destination.rr;
1411 else
1412 drr = c->playc->destination.ri;
1413 if (srr == drr)
1414 mmul1 = mmul;
1415 else
1416 mmul1 = (exp(log(srr) + ((log(drr) - log(srr)) * mmul)) - srr) /
1417 (drr - srr);
1418 if (mmul1 > 1)
1419 mmul1 = 1;
1420 if (mmul1 < 0)
1421 mmul1 = 0;
1422 inmovement = 1;
1423 c->fcontext->s.rr =
1424 c->playc->source.rr +
1425 (c->playc->destination.rr - c->playc->source.rr) * mmul1;
1426 c->fcontext->s.ri =
1427 c->playc->source.ri +
1428 (c->playc->destination.ri - c->playc->source.ri) * mmul1;
1429 c->fcontext->s.cr =
1430 c->playc->source.cr +
1431 (c->playc->destination.cr - c->playc->source.cr) * mmul1;
1432 c->fcontext->s.ci =
1433 c->playc->source.ci +
1434 (c->playc->destination.ci - c->playc->source.ci) * mmul1;
1435 uih_animate_image(c);
1436 }
1437 if (c->playc->morphjulia) {
1438 int timer = tl_lookup_timer(c->playc->timer) - c->playc->starttime;
1439 number_t mmul = /*(tl_lookup_timer (c->playc->timer) -
1440 c->playc->starttime) / (number_t)
1441 (c->playc->frametime - c->playc->starttime); */
1442 MORPHVALUE(timer, c->playc->frametime - c->playc->starttime,
1443 c->playc->morphjuliatimes[0],
1444 c->playc->morphjuliatimes[1]);
1445 uih_setjuliaseed(
1446 uih, c->playc->sr + (c->playc->dr - c->playc->sr) * mmul,
1447 c->fcontext->pim =
1448 c->playc->si + (c->playc->di - c->playc->si) * mmul);
1449 inmovement = 1;
1450 }
1451 if (c->playc->morphangle) {
1452 int timer = tl_lookup_timer(c->playc->timer) - c->playc->starttime;
1453 number_t mmul = /*(tl_lookup_timer (c->playc->timer) -
1454 c->playc->starttime) / (number_t)
1455 (c->playc->frametime - c->playc->starttime); */
1456 MORPHVALUE(timer, c->playc->frametime - c->playc->starttime,
1457 c->playc->morphangletimes[0],
1458 c->playc->morphangletimes[1]);
1459 uih_angle(uih,
1460 c->playc->srcangle +
1461 (c->playc->destangle - c->playc->srcangle) * mmul);
1462 inmovement = 1;
1463 }
1464 } else {
1465 if (!c->juliamode) {
1466 if (c->autopilot) { /*now handle autopilot */
1467 mousex = c->autopilotx;
1468 mousey = c->autopiloty;
1469 mousebuttons = c->autopilotbuttons;
1470 inmovement = 1;
1471 }
1472 if (c->step) {
1473 number_t x;
1474 number_t y;
1475 if (mousex != c->xcenterm || mousey != c->ycenterm) {
1476 c->xcenterm = mousex;
1477 c->ycenterm = mousey;
1478 uih_getcoord(uih, mousex, mousey, &x, &y);
1479 c->xcenter = x;
1480 c->ycenter = y;
1481 }
1482 uih_zoomupdate(c), inmovement = 1;
1483 }
1484 c->zoomactive = 0;
1485 if (c->rotatemode != ROTATE_MOUSE)
1486 switch (mousebuttons) { /*process buttons */
1487 case BUTTON1:
1488 c->zoomactive = 1;
1489 inmovement = 1;
1490 break;
1491 case BUTTON3:
1492 c->zoomactive = -1;
1493 inmovement = 1;
1494 break;
1495 }
1496 uih_saveframe(c);
1497 if (c->rotatemode != ROTATE_MOUSE) {
1498 c->rotatepressed = 0;
1499 switch (mousebuttons) { /*process buttons */
1500 case BUTTON1:
1501 uih_zoom(c), slowdown = 0;
1502 break;
1503 case BUTTON3:
1504 uih_unzoom(c), slowdown = 0;
1505 break;
1506 case BUTTON2: { /* handles panning */
1507 number_t x, y;
1508 uih_getcoord(uih, mousex, mousey, &x, &y);
1509 if (c->pressed && (c->oldx != x || c->oldy != y)) {
1510 c->fcontext->s.cr -= x - c->oldx;
1511 c->fcontext->s.ci -= y - c->oldy;
1512 uih_animate_image(c);
1513 c->moved = 1;
1514 }
1515 c->speed = 0;
1516
1517 /* issue 115 - disable rotation to update panning */
1518 if(c->pressed == 0) {
1519 int old_mode = c->rotatemode;
1520 uih_rotate(c, 0);
1521 uih_getcoord(uih, mousex, mousey, &c->oldx, &c->oldy);
1522 uih_rotate(c, old_mode);
1523 }
1524 c->pressed = 1;
1525 } break;
1526 }
1527 } else {
1528 if (mousebuttons & BUTTON1) {
1529 number_t x, y;
1530 number_t angle;
1531
1532 x = (mousex - c->image->width / 2) * c->image->pixelwidth;
1533 y = (mousey - c->image->height / 2) * c->image->pixelheight;
1534 angle = -atan2(x, y) * 180 / M_PI;
1535 if (c->rotatepressed) {
1536 uih_angle(uih,
1537 c->fcontext->angle + angle - c->oldangle);
1538 }
1539 c->rotatepressed = 1;
1540 c->oldangle = angle;
1541 } else if (mousebuttons & BUTTON2) {
1542 number_t x, y;
1543 uih_getcoord(uih, mousex, mousey, &x, &y);
1544 if (c->pressed && (c->oldx != x || c->oldy != y)) {
1545 c->fcontext->s.cr -= x - c->oldx;
1546 c->fcontext->s.ci -= y - c->oldy;
1547 uih_animate_image(c);
1548 c->moved = 1;
1549 }
1550 c->speed = 0;
1551
1552 /* issue 115 - disable rotation to update panning */
1553 if(c->pressed == 0) {
1554 int old_mode = c->rotatemode;
1555 uih_rotate(c, 0);
1556 uih_getcoord(uih, mousex, mousey, &c->oldx, &c->oldy);
1557 uih_rotate(c, old_mode);
1558 }
1559 c->pressed = 1;
1560 } else
1561 c->rotatepressed = 0;
1562 }
1563 if (!(mousebuttons & BUTTON2))
1564 c->pressed = 0;
1565 if (slowdown)
1566 uih_slowdown(c);
1567 } else {
1568 if (mousebuttons & BUTTON1) {
1569 number_t x, x1 = c->fcontext->pre;
1570 number_t y, y1 = c->fcontext->pim;
1571 c->zoomactive = 0;
1572 uih_getcoord(uih, mousex, mousey, &x, &y);
1573 c->fcontext->pre = x;
1574 c->fcontext->pim = y;
1575 uih_saveframe(c);
1576 c->pressed = 1;
1577 recalculate(c->fcontext->plane, &c->fcontext->pre,
1578 &c->fcontext->pim);
1579 if (c->fcontext->pre != x1 || c->fcontext->pim != y1) {
1580 uih_animate_image(c);
1581 }
1582 } else
1583 c->pressed = 0;
1584 }
1585 }
1586 if (!inmovement)
1587 uih_tbreak(c);
1588 if (c->incomplete)
1589 inmovement = 1;
1590 if (!c->recalculatemode && !c->display)
1591 uih_finishpalette(c);
1592 if (!inmovement)
1593 uih_callcomplette(c);
1594 if (c->inanimation < inmovement * 2)
1595 c->inanimation = inmovement * 2;
1596 return (inmovement * 2);
1597 }
1598
1599 /*actions that can be used be user interface */
1600
uih_autopilot_on(uih_context * c)1601 void uih_autopilot_on(uih_context *c)
1602 {
1603 if (!c->autopilot) {
1604 clean_autopilot(c);
1605 uih_autopilothandler(c, 1);
1606 tl_update_time();
1607 uih_resumetimers(c);
1608 c->autopilottimer = tl_create_timer();
1609 c->autopilotgroup = tl_create_group();
1610 tl_set_multihandler(c->autopilottimer, uih_autopilothandler, c);
1611 tl_set_interval(c->autopilottimer, 1000000 / 25);
1612 tl_reset_timer(c->autopilottimer);
1613 tl_add_timer(c->autopilotgroup, c->autopilottimer);
1614 tl_update_time();
1615 c->autopilot = 1;
1616 uih_emulatetimers(c);
1617 uih_updatemenus(c, "autopilot");
1618 }
1619 }
1620
uih_autopilot_off(uih_context * c)1621 void uih_autopilot_off(uih_context *c)
1622 {
1623 if (c->autopilot) {
1624 tl_remove_timer(c->autopilottimer);
1625 tl_free_timer(c->autopilottimer);
1626 tl_free_group(c->autopilotgroup);
1627 c->autopilot = 0;
1628 uih_updatemenus(c, "autopilot");
1629 }
1630 }
1631
uih_mkdefaultpalette(uih_context * c)1632 void uih_mkdefaultpalette(uih_context *c)
1633 {
1634 if (c->zengine->fractalc->palette == NULL)
1635 return;
1636 uih_cycling_stop(c);
1637 if (mkdefaultpalette(c->zengine->fractalc->palette) != 0) {
1638 uih_newimage(c);
1639 }
1640 uih_palettechg(c);
1641 c->paletteshift = 0;
1642 c->manualpaletteshift = 0;
1643 c->palettechanged = 1;
1644 c->palettetype = 0;
1645 uih_finishpalette(c);
1646 uih_cycling_continue(c);
1647 }
1648
uih_mkpalette(uih_context * c)1649 void uih_mkpalette(uih_context *c)
1650 {
1651 int seed;
1652 int alg = rand() % PALGORITHMS;
1653 if (c->zengine->fractalc->palette == NULL)
1654 return;
1655 uih_cycling_stop(c);
1656 if (mkpalette(c->zengine->fractalc->palette, seed = rand(), alg) != 0) {
1657 uih_newimage(c);
1658 }
1659 uih_palettechg(c);
1660 c->paletteshift = 0;
1661 c->manualpaletteshift = 0;
1662 c->paletteseed = seed;
1663 uih_finishpalette(c);
1664 c->palettechanged = 1;
1665 c->palettetype = alg + 1;
1666 uih_cycling_continue(c);
1667 }
1668
1669 /*Basic inicialization routines */
1670
uih_alloctables(uih_context * c)1671 static void uih_alloctables(uih_context *c)
1672 {
1673 c->zengine = zoom_filter.getinstance(&zoom_filter);
1674 if (c->zengine == NULL)
1675 return;
1676 c->fcontext = make_fractalc(0, c->image->pixelwidth * c->image->width,
1677 c->image->pixelheight * c->image->height);
1678 uih_updatemenus(c, "periodicity") uih_updatemenus(c, "in0")
1679 uih_updatemenus(c, "int0") uih_updatemenus(c, "out0")
1680 uih_updatemenus(c, "outt0") uih_updatemenus(c, "plane0")
1681 uih_updatemenus(c, "guess3") uih = c;
1682 c->uifilter = uih_filter.getinstance(&uih_filter);
1683 c->queue = create_queue(c->uifilter);
1684 insertfilter(c->zengine, c->uifilter);
1685 }
1686
uih_initqueue(uih_context * c)1687 static int uih_initqueue(uih_context *c) { return (initqueue(c->queue)); }
1688
uih_setmaxstep(uih_context * c,number_t p)1689 void uih_setmaxstep(uih_context *c, number_t p) { c->maxstep = p; }
1690
uih_setspeedup(uih_context * c,number_t p)1691 void uih_setspeedup(uih_context *c, number_t p) { c->speedup = p; }
1692
uih_setmaxiter(uih_context * c,int maxiter)1693 void uih_setmaxiter(uih_context *c, int maxiter)
1694 {
1695 if (maxiter < 1)
1696 maxiter = 1;
1697 if (maxiter > 2000000)
1698 maxiter = 2000000;
1699 if (c->fcontext->maxiter != (unsigned int)maxiter) {
1700 c->fcontext->maxiter = maxiter;
1701 c->fcontext->version++;
1702 uih_newimage(c);
1703 }
1704 }
1705
uih_setbailout(uih_context * c,number_t bailout)1706 void uih_setbailout(uih_context *c, number_t bailout)
1707 {
1708 if (bailout < 0)
1709 bailout = 0;
1710 if (c->fcontext->bailout != (number_t)bailout) {
1711 c->fcontext->bailout = bailout;
1712 c->fcontext->version++;
1713 uih_newimage(c);
1714 }
1715 }
1716
uih_setincoloringmode(uih_context * c,int mode)1717 void uih_setincoloringmode(uih_context *c, int mode)
1718 {
1719 if (mode < 0)
1720 mode = rand() % INCOLORING;
1721 if (mode > INCOLORING)
1722 mode = INCOLORING;
1723 if (c->fcontext->incoloringmode != mode) {
1724 char str[10];
1725 c->fcontext->incoloringmode = mode;
1726 c->fcontext->version++;
1727 uih_newimage(c);
1728 sprintf(str, "in%i", mode);
1729 uih_updatemenus(c, str);
1730 }
1731 }
1732
uih_setintcolor(uih_context * c,int mode)1733 void uih_setintcolor(uih_context *c, int mode)
1734 {
1735 if (mode < 0)
1736 mode = rand() % TCOLOR;
1737 if (mode > TCOLOR)
1738 mode = TCOLOR;
1739 if (c->fcontext->intcolor != mode) {
1740 char str[10];
1741 c->fcontext->intcolor = mode;
1742 if (c->fcontext->incoloringmode == 10) {
1743 c->fcontext->version++;
1744 uih_newimage(c);
1745 }
1746 sprintf(str, "int%i", mode);
1747 uih_updatemenus(c, str);
1748 }
1749 }
1750
uih_setouttcolor(uih_context * c,int mode)1751 void uih_setouttcolor(uih_context *c, int mode)
1752 {
1753 if (mode < 0)
1754 mode = rand() % TCOLOR;
1755 if (mode > TCOLOR)
1756 mode = TCOLOR;
1757 if (c->fcontext->outtcolor != mode) {
1758 char str[10];
1759 c->fcontext->outtcolor = mode;
1760 if (c->fcontext->coloringmode == 10) {
1761 c->fcontext->version++;
1762 uih_newimage(c);
1763 }
1764 sprintf(str, "outt%i", mode);
1765 uih_updatemenus(c, str);
1766 }
1767 }
1768
uih_setperbutation(uih_context * c,number_t zre,number_t zim)1769 void uih_setperbutation(uih_context *c, number_t zre, number_t zim)
1770 {
1771 if (c->fcontext->bre != zre || c->fcontext->bim != zim) {
1772 c->fcontext->bre = zre;
1773 c->fcontext->bim = zim;
1774 if (c->fcontext->mandelbrot) {
1775 c->fcontext->version++;
1776 uih_newimage(c);
1777 }
1778 uih_updatemenus(c, "uiperturbation");
1779 }
1780 }
1781
uih_perbutation(uih_context * c,int mousex,int mousey)1782 void uih_perbutation(uih_context *c, int mousex, int mousey)
1783 {
1784 number_t r, i;
1785 uih_getcoord(c, mousex, mousey, &r, &i);
1786 uih_setperbutation(c, r, i);
1787 }
1788
uih_setjuliaseed(uih_context * c,number_t zre,number_t zim)1789 void uih_setjuliaseed(uih_context *c, number_t zre, number_t zim)
1790 {
1791 if (c->fcontext->pre != zre || c->fcontext->pim != zim) {
1792 c->fcontext->pre = zre;
1793 c->fcontext->pim = zim;
1794 if (c->juliamode) {
1795 uih_animate_image(c);
1796 } else {
1797 if (!c->fcontext->mandelbrot) {
1798 c->fcontext->version++;
1799 if (c->playc && c->playc->morphjulia)
1800 uih_animate_image(c);
1801 else
1802 uih_newimage(c);
1803 }
1804 }
1805 }
1806 }
1807
uih_setfastmode(uih_context * c,int mode)1808 void uih_setfastmode(uih_context *c, int mode)
1809 {
1810 const char *names[] = {"nodynamic", "nodynamic", "dynamicanimation",
1811 "dynamicnew", "dynamicnew"};
1812 if (mode < 0)
1813 mode = 0;
1814 c->fastmode = mode;
1815 uih_updatemenus(c, names[mode]);
1816 }
1817
uih_setoutcoloringmode(uih_context * c,int mode)1818 void uih_setoutcoloringmode(uih_context *c, int mode)
1819 {
1820 if (mode < 0)
1821 mode = rand() % OUTCOLORING;
1822 if (mode > OUTCOLORING)
1823 mode = OUTCOLORING - 1;
1824 if (c->fcontext->coloringmode != mode) {
1825 char str[10];
1826 c->fcontext->coloringmode = mode;
1827 c->fcontext->version++;
1828 uih_newimage(c);
1829 sprintf(str, "out%i", mode);
1830 uih_updatemenus(c, str);
1831 }
1832 }
1833
uih_setplane(uih_context * c,int mode)1834 void uih_setplane(uih_context *c, int mode)
1835 {
1836 int i;
1837
1838 if (mode < 0)
1839 mode = 0;
1840 for (i = 0; planename[i] != NULL; i++)
1841 ;
1842 if (mode >= i)
1843 mode = i - 1;
1844 if (mode < 0)
1845 mode = rand() % i;
1846 uih_invalidatepos(c);
1847 if (c->fcontext->plane != mode) {
1848 char str[20];
1849 c->fcontext->plane = mode;
1850 // if ( c->fcontext->plane == P_USER )
1851 // printf("USER NOT IMPLEMENTED");
1852 // uih_sffein( c, "z^3-c" )
1853 c->fcontext->version++;
1854 uih_newimage(c);
1855 sprintf(str, "plane%i", mode);
1856 uih_updatemenus(c, str);
1857 }
1858 }
1859
uih_screentofractalcoord(uih_context * c,int mousex,int mousey,number_t * re,number_t * im)1860 void uih_screentofractalcoord(uih_context *c, int mousex, int mousey,
1861 number_t *re, number_t *im)
1862 {
1863 uih_getcoord(c, mousex, mousey, re, im);
1864 recalculate(c->fcontext->plane, re, im);
1865 }
1866
uih_setmandelbrot(uih_context * c,int mode,int mousex,int mousey)1867 void uih_setmandelbrot(uih_context *c, int mode, int mousex, int mousey)
1868 {
1869 if (mode < 0)
1870 mode = 0;
1871 if (mode > 1)
1872 mode = 1;
1873 if (c->fcontext->mandelbrot != mode) {
1874 c->fcontext->mandelbrot = mode;
1875 if (c->fcontext->mandelbrot == 0 && !c->juliamode) {
1876 uih_getcoord(c, mousex, mousey, &c->fcontext->pre,
1877 &c->fcontext->pim);
1878 recalculate(c->fcontext->plane, &c->fcontext->pre,
1879 &c->fcontext->pim);
1880 } else
1881 uih_disablejulia(c);
1882 c->fcontext->version++;
1883 uih_newimage(c);
1884 uih_updatemenus(c, "uimandelbrot");
1885 }
1886 }
1887
uih_setguessing(uih_context * c,int range)1888 void uih_setguessing(uih_context *c, int range)
1889 {
1890 char str[10];
1891 c->fcontext->range = range;
1892 if (range <= 1) {
1893 uih_updatemenus(c, "noguess");
1894 } else if (range > 8) {
1895 uih_updatemenus(c, "guessall");
1896 } else {
1897 sprintf(str, "guess%i", range);
1898 uih_updatemenus(c, str);
1899 }
1900 }
1901
uih_setperiodicity(uih_context * c,int periodicity)1902 void uih_setperiodicity(uih_context *c, int periodicity)
1903 {
1904 c->fcontext->periodicity = periodicity;
1905 uih_updatemenus(c, "periodicity");
1906 }
1907
uih_interrupt(uih_context * c)1908 void uih_interrupt(uih_context *c)
1909 {
1910 if (c->incalculation)
1911 c->interrupt = 1;
1912 }
1913
uih_stopzooming(uih_context * c)1914 void uih_stopzooming(uih_context *c) { c->speed = 0; }
1915
uih_updateimage(uih_context * c,struct image * image)1916 int uih_updateimage(uih_context *c, struct image *image)
1917 {
1918 /*exit(); */
1919 c->image = image;
1920 c->palette = image->palette;
1921 c->queue->isinitialized = 0;
1922 c->ddatalost = 1;
1923 fractalc_resize_to(c->fcontext, c->image->pixelwidth * c->image->width,
1924 c->image->pixelheight * c->image->height);
1925 c->display = 1;
1926 c->palette->ncells = sizeof(uicolors) / sizeof(rgb_t);
1927 c->palette->prergb = uicolors;
1928 if (c->palette->type & BITMAPS)
1929 c->palette->prergb = uibwcolors;
1930 c->inanimation = 2;
1931 uih_newimage(c);
1932 if (image->palette->type & (FIXEDCOLOR | BITMAPS))
1933 uih_fixedcolorenable(c);
1934 else
1935 uih_fixedcolordisable(c);
1936 return (uih_initqueue(c));
1937 }
1938
uih_getcscreensizes(struct uih_context * uih,int * x,int * y,int * w,int * h,void *)1939 static void uih_getcscreensizes(struct uih_context *uih, int *x, int *y, int *w,
1940 int *h, void * /*data*/)
1941 {
1942 *x = 0;
1943 *y = 0;
1944 if (uih->clearscreen)
1945 *w = uih->image->width, *h = uih->image->height;
1946 else
1947 *w = *h = 0;
1948 }
1949
uih_drawcscreen(struct uih_context * uih,void *)1950 static void uih_drawcscreen(struct uih_context *uih, void * /*data*/)
1951 {
1952 if (uih->clearscreen)
1953 clear_image(uih->image);
1954 }
1955
1956 struct uih_context *
uih_mkcontext(int flags,struct image * image,int (* passfunc)(struct uih_context *,int,const char *,float),void (* longwait)(struct uih_context *),void (* upd)(struct uih_context *,const char *))1957 uih_mkcontext(int flags, struct image *image,
1958 int (*passfunc)(struct uih_context *, int, const char *, float),
1959 void (*longwait)(struct uih_context *),
1960 void (*upd)(struct uih_context *, const char *))
1961 {
1962 uih_context *uih;
1963 uih = (uih_context *)calloc(sizeof(*uih), 1); /*setup parameters */
1964 uih->updatemenus = upd;
1965 uih->autopilot = 0;
1966 uih->flags = flags;
1967 uih->image = image;
1968 uih->playstring = NULL;
1969 uih->palette = image->palette;
1970 uih->menuroot = "root";
1971 uih->palette->ncells = sizeof(uicolors) / sizeof(rgb_t);
1972 uih->palette->prergb = uicolors;
1973 if (uih->palette->type & BITMAPS) {
1974 uih->palette->prergb = uibwcolors;
1975 }
1976 uih->speed = 0;
1977 uih->step = 0;
1978 uih->color = 0;
1979 uih->speedup = STEP;
1980 uih->maxstep = MAXSTEP;
1981 uih->lasttime = -1;
1982 uih->recalculatemode = UIH_NEW_IMAGE;
1983 uih->display = 1;
1984 uih->fastmode = 2;
1985 uih_updatemenus(uih, "dynamicanimation");
1986 uih->aliasnum = -1;
1987 uih->direction = 1;
1988 uih->cyclingdirection = 1;
1989 uih->cyclingspeed = ROTATIONSPEED;
1990 uih->ddatalost = 1;
1991 uih->xtextpos = 1;
1992 uih_updatemenus(uih, "xtextleft");
1993 uih->complettehandler = 0;
1994 uih->ytextpos = 1;
1995 uih_updatemenus(uih, "ytextup");
1996 uih->display = 0;
1997 uih->errstring = NULL;
1998 uih->rotatemode = 0;
1999 uih_updatemenus(uih, "norotate");
2000 uih->rotationspeed = 10;
2001 uih->longwait = longwait;
2002 uih->passfunc = passfunc;
2003 uih->nletters = 0;
2004 uih->letterspersec = 15;
2005 uih->maintimer = tl_create_timer();
2006 uih->calculatetimer = tl_create_timer();
2007 uih->doittimer = tl_create_timer();
2008 tl_update_time();
2009 tl_reset_timer(uih->maintimer);
2010 tl_reset_timer(uih->calculatetimer);
2011 tl_stop_timer(uih->doittimer);
2012 tl_reset_timer(uih->doittimer);
2013 uih_alloctables(uih);
2014 uih_initqueue(uih); /*FIXME return value should not be ignored */
2015 if (image->palette->type & (FIXEDCOLOR | BITMAPS))
2016 uih_fixedcolorenable(uih);
2017 uih_mkdefaultpalette(uih);
2018 uih_stoptimers(uih);
2019 clean_autopilot(uih);
2020 uih_newimage(uih);
2021 uih->cscreenwindow = uih_registerw(uih, uih_getcscreensizes,
2022 uih_drawcscreen, 0, NONTRANSPARENTW);
2023 uih_initmessages(uih);
2024 uih_inittext(uih);
2025 uih_emulatetimers(uih);
2026 #ifdef USE_SFFE
2027 sffe_parse(&uih->fcontext->userformula, USER_FORMULA);
2028 sffe_parse(&uih->fcontext->userinitial, "");
2029 #endif
2030 uih_setformula(uih, 0);
2031 uih_saveundo(uih);
2032 return (uih);
2033 }
2034
uih_savepalette(uih_context * c)2035 void uih_savepalette(uih_context *c)
2036 {
2037 if (c->palette2 != NULL)
2038 destroypalette(c->palette2);
2039 if (c->zengine->fractalc->palette != NULL)
2040 c->palette2 = clonepalette(c->zengine->fractalc->palette);
2041 }
2042
uih_restorepalette(uih_context * uih)2043 void uih_restorepalette(uih_context *uih)
2044 {
2045 if (uih->palette2 != NULL) {
2046 if (uih->zengine->fractalc->palette != NULL)
2047 restorepalette(uih->zengine->fractalc->palette, uih->palette2);
2048 destroypalette(uih->palette2);
2049 }
2050 uih->palette2 = NULL;
2051 uih_finishpalette(uih);
2052 }
2053
uih_loadpalette(uih_context * c,struct palette * palette)2054 void uih_loadpalette(uih_context *c, struct palette *palette)
2055 {
2056 if (c->palette2)
2057 destroypalette(c->palette2);
2058 c->palette2 = clonepalette(palette);
2059 uih_restorepalette(c);
2060 uih_palettechg(c);
2061 }
2062
uih_clonepalette(uih_context * c)2063 struct palette *uih_clonepalette(uih_context *c)
2064 {
2065 if (c->zengine->fractalc->palette != NULL)
2066 return clonepalette(c->zengine->fractalc->palette);
2067 // I hope this is OK:
2068 return NULL;
2069 }
2070
uih_setformula(uih_context * c,int num)2071 void uih_setformula(uih_context *c, int num)
2072 {
2073 set_formula(c->fcontext, num);
2074 uih_newimage(c);
2075 uih_updatemenus(c, "uimandelbrot");
2076 uih_updatemenus(c, "uiperturbation");
2077 uih_updatemenus(c, c->fcontext->currentformula->shortname);
2078 }
2079
uih_sffeset(uih_context * c,sffe * parser,const char * formula)2080 void uih_sffeset(uih_context *c, sffe *parser, const char *formula)
2081 {
2082 char error[200];
2083 char previous[200];
2084 if (c->fcontext->userformula->expression)
2085 strcpy(previous, c->fcontext->userformula->expression);
2086 else
2087 strcpy(previous, USER_FORMULA);
2088 parser->errormsg = error;
2089 int errorcode = sffe_parse(&parser, formula);
2090 if (errorcode > 0) {
2091 if (errorcode != EmptyFormula || parser != c->fcontext->userinitial) {
2092 tl_update_time(); // otherwise error doesn't display long enough
2093 uih_error(c, error);
2094 sffe_parse(&parser, previous);
2095 }
2096 } else {
2097 if (parser->expression)
2098 uih_message(c, parser->expression);
2099 sffe_setlocal(c->fcontext);
2100 if (!(c->fcontext->currentformula->flags & SFFE_FRACTAL)) {
2101 uih_play_formula(c, "user");
2102 } else {
2103 uih_recalculate(c);
2104 }
2105 }
2106 parser->errormsg = NULL;
2107 }
2108
uih_initstate(struct uih_context * uih)2109 void uih_initstate(struct uih_context *uih)
2110 {
2111 int i;
2112 int ver = uih->fcontext->version;
2113 uih->step = 0;
2114 uih->speedup = STEP;
2115 uih->maxstep = MAXSTEP;
2116 uih_fastrotatedisable(uih);
2117 uih_disablejulia(uih);
2118 uih->color = 0;
2119 uih_cycling_off(uih);
2120 for (i = 0; i < uih_nfilters; i++)
2121 uih_disablefilter(uih, i);
2122 uih_setperbutation(uih, 0, 0);
2123 set_formula(uih->fcontext, 0);
2124 #ifdef USE_SFFE
2125 sffe_parse(&uih->fcontext->userformula, USER_FORMULA);
2126 sffe_parse(&uih->fcontext->userinitial, "");
2127 #endif
2128 uih_setperiodicity(uih, 1);
2129 uih_setmaxiter(uih, 170);
2130 uih_setbailout(uih, 4);
2131 uih_setincoloringmode(uih, 0);
2132 uih_setoutcoloringmode(uih, 0);
2133 uih_setcycling(uih, 30);
2134 uih_display(uih);
2135 uih_setfastmode(uih, 2);
2136 uih_setintcolor(uih, 0);
2137 uih_setouttcolor(uih, 0);
2138 uih_setplane(uih, 0);
2139 uih_setguessing(uih, 3);
2140 uih_angle(uih, 0);
2141 uih_rotatemode(uih, 0);
2142 uih_rotationspeed(uih, 10);
2143 uih->xtextpos = 1;
2144 uih->ytextpos = 1;
2145 if (uih->playc) {
2146 uih->playc->morphtimes[0] = 0;
2147 uih->playc->morphtimes[1] = 0;
2148 uih->playc->morphjuliatimes[0] = 0;
2149 uih->playc->morphjuliatimes[1] = 0;
2150 uih->playc->morphangletimes[0] = 0;
2151 uih->playc->morphangletimes[1] = 0;
2152 uih->playc->morphlinetimes[0] = 0;
2153 uih->playc->morphlinetimes[1] = 0;
2154 }
2155 if (mkdefaultpalette(uih->zengine->fractalc->palette) != 0 ||
2156 uih->recalculatemode || uih->fcontext->version != ver) {
2157 uih_newimage(uih);
2158 }
2159 }
2160
uih_freecontext(uih_context * c)2161 void uih_freecontext(uih_context *c)
2162 {
2163 struct filter *f;
2164 int i;
2165 if (c->emulator != NULL)
2166 uih_noconstantframetime(c);
2167 for (i = 0; i < UNDOLEVEL; i++)
2168 if (c->undo.undos[i])
2169 free(c->undo.undos[i]), c->undo.undos[i] = 0;
2170 while (c->queue->first) {
2171 f = c->queue->first;
2172 removefilter(c->queue->first);
2173 f->action->destroyinstance(f);
2174 }
2175 uih_destroymessages(c);
2176 uih_destroytext(c);
2177 uih_removew(c, c->cscreenwindow);
2178 free(c->queue);
2179 free_fractalc(c->fcontext);
2180 free(c);
2181 }
2182
uih_getinstance(const struct filteraction * a)2183 static struct filter *uih_getinstance(const struct filteraction *a)
2184 {
2185 struct filter *f = createfilter(a);
2186 f->data = uih;
2187 f->name = "XaoS's user interface layer";
2188 return (f);
2189 }
2190
uih_destroyinstance(struct filter * f)2191 static void uih_destroyinstance(struct filter *f)
2192 {
2193 struct uih_context *c = (struct uih_context *)f->data;
2194 if (c->autopilot)
2195 uih_autopilot_off(c);
2196 if (c->cycling)
2197 uih_cycling_off(c);
2198 tl_free_timer(c->maintimer);
2199 tl_free_timer(c->calculatetimer);
2200 tl_free_timer(c->doittimer);
2201 if (c->save)
2202 uih_save_disable(c);
2203 if (c->play)
2204 uih_replaydisable(c);
2205 free(f);
2206 }
2207
2208 static int wascycling;
uih_require(struct filter * f,struct requirements * r)2209 static int uih_require(struct filter *f, struct requirements *r)
2210 {
2211 struct uih_context *uih;
2212 uih = (struct uih_context *)f->data;
2213 f->req = *r;
2214 uih_clearwindows(uih);
2215 if (uih->cycling)
2216 uih_cycling_off(uih), wascycling = 1;
2217 if (!(r->supportedmask & uih->image->palette->type))
2218 return 0;
2219 /*FIXME something should be done here :) */
2220 return (1);
2221 }
2222
uih_initialize(struct filter * f,struct initdata * i)2223 static int uih_initialize(struct filter *f, struct initdata *i)
2224 {
2225 struct uih_context *uih;
2226 int returnval;
2227 uih = (struct uih_context *)f->data;
2228 f->queue->saveimage = uih->image;
2229 i->fractalc = uih->fcontext;
2230 uih_setfont(uih);
2231 tl_update_time();
2232 f->image = uih->image;
2233 f->wait_function = uih_waitfunc;
2234 uih->times[0][0] = -1;
2235 i->image = uih->image;
2236 f->fractalc = i->fractalc;
2237 f->image->palette->flags |= FINISHLATER;
2238 i->fractalc->palette = uih->image->palette;
2239 i->wait_function = uih_waitfunc;
2240 /*FIXME datalost should be handled in better way */
2241 if (uih->ddatalost)
2242 i->flags |= DATALOST;
2243 uih->tbreak = 2;
2244 uih_invalidatepos(uih);
2245 clean_autopilot(uih);
2246 returnval = f->previous->action->initialize(f->previous, i);
2247 if (wascycling)
2248 uih_cycling_on(uih), wascycling = 0;
2249 return returnval;
2250 }
2251
uih_inhibittextsw(uih_context * c)2252 void uih_inhibittextsw(uih_context *c)
2253 {
2254 c->inhibittextoutput ^= 1;
2255 uih_updatemenus(c, "inhibittextoutput");
2256 }
2257
uih_inhibittextselected(uih_context * c)2258 int uih_inhibittextselected(uih_context *c)
2259 {
2260 if (c == NULL)
2261 return 0;
2262 return c->inhibittextoutput;
2263 }
2264
2265 static char statustext[256];
2266 static int statusstart;
2267 static struct uih_window *statuswindow = NULL;
2268 static int ministatusstart;
2269 static struct uih_window *ministatuswindow = NULL;
2270 static struct uih_window *cartesiangridwindow = NULL;
2271
uih_updatestatus(uih_context * uih)2272 void uih_updatestatus(uih_context *uih)
2273 {
2274 double times =
2275 (uih->fcontext->currentformula->v.rr) / (uih->fcontext->s.rr);
2276 double timesnop = log(times) / log(10.0);
2277 double speed;
2278 uih_drawwindows(uih);
2279 uih_cycling_continue(uih);
2280 speed = uih_displayed(uih);
2281 sprintf(
2282 statustext,
2283 TR("Message",
2284 "%s %.2f times (%.1fE) %2.2f frames/sec %c %i %i %i %u "),
2285 times < 1 ? TR("Message", "unzoomed") : TR("Message", "zoomed"),
2286 times < 1 ? 1.0 / times : times, timesnop, speed,
2287 uih->autopilot ? 'A' : ' ', uih->fcontext->coloringmode + 1,
2288 uih->fcontext->incoloringmode + 1, uih->fcontext->plane + 1,
2289 uih->fcontext->maxiter);
2290
2291 STAT(printf(TR("Message", "framerate:%f\n"), speed));
2292 }
2293
2294 #ifdef MEMCHECK
2295 #define STATUSLINES 13
2296 #else
2297 #define STATUSLINES 11
2298 #endif
2299
uih_updatestarts(uih_context * uih)2300 void uih_updatestarts(uih_context *uih)
2301 {
2302 int y = 0;
2303 ministatusstart = y;
2304 if (ministatuswindow != NULL)
2305 y += xtextheight(uih->image, uih->font);
2306 statusstart = y;
2307 if (statuswindow != NULL)
2308 y += xtextheight(uih->image, uih->font) * STATUSLINES;
2309 uih->messg.messagestart = y;
2310 }
2311
uih_statuspos(uih_context * uih,int * x,int * y,int * w,int * h,void *)2312 static void uih_statuspos(uih_context *uih, int *x, int *y, int *w, int *h,
2313 void * /*data*/)
2314 {
2315 *x = 0;
2316 *y = statusstart;
2317 *w = uih->image->width;
2318 *h = xtextheight(uih->image, uih->font) * STATUSLINES;
2319 }
2320
uih_drawstatus(uih_context * uih,void *)2321 static void uih_drawstatus(uih_context *uih, void * /*data*/)
2322 {
2323 char str[6000];
2324 int h = xtextheight(uih->image, uih->font);
2325 sprintf(str, TR("Message", "Fractal name:%s"),
2326 uih->fcontext->currentformula->name[!uih->fcontext->mandelbrot]);
2327 xprint(uih->image, uih->font, 0, statusstart, str, FGCOLOR(uih),
2328 BGCOLOR(uih), 0);
2329 sprintf(str, TR("Message", "Fractal type:%s"),
2330 uih->fcontext->mandelbrot ? TR("Message", "Mandelbrot")
2331 : TR("Message", "Julia"));
2332 #ifdef USE_SFFE
2333 if (uih->fcontext->currentformula->flags & SFFE_FRACTAL &&
2334 uih->fcontext->userformula->expression) {
2335 sprintf(str, TR("Message", "Formula:%s"),
2336 uih->fcontext->userformula->expression);
2337 };
2338 #endif
2339 xprint(uih->image, uih->font, 0, statusstart + h, str, FGCOLOR(uih),
2340 BGCOLOR(uih), 0);
2341 sprintf(str, TR("Message", "View:[%1.12f,%1.12f]"),
2342 (double)uih->fcontext->s.cr, (double)uih->fcontext->s.ci);
2343 xprint(uih->image, uih->font, 0, statusstart + 2 * h, str, FGCOLOR(uih),
2344 BGCOLOR(uih), 0);
2345 sprintf(str, TR("Message", "size:[%1.12f,%1.12f]"),
2346 (double)uih->fcontext->s.rr, (double)uih->fcontext->s.ri);
2347 xprint(uih->image, uih->font, 0, statusstart + 3 * h, str, FGCOLOR(uih),
2348 BGCOLOR(uih), 0);
2349 sprintf(str, TR("Message", "Rotation:%4.2f Screen size:%i:%i"),
2350 (double)uih->fcontext->angle, uih->image->width,
2351 uih->image->height);
2352 xprint(uih->image, uih->font, 0, statusstart + 4 * h, str, FGCOLOR(uih),
2353 BGCOLOR(uih), 0);
2354 sprintf(str, TR("Message", "Iterations:%-4u Palette size:%i"),
2355 uih->fcontext->maxiter, uih->image->palette->size);
2356 xprint(uih->image, uih->font, 0, statusstart + 5 * h, str, FGCOLOR(uih),
2357 BGCOLOR(uih), 0);
2358 sprintf(str, TR("Message", "Bailout:%4.2f"),
2359 (double)uih->fcontext->bailout);
2360 xprint(uih->image, uih->font, 0, statusstart + 6 * h, str, FGCOLOR(uih),
2361 BGCOLOR(uih), 0);
2362 sprintf(str, TR("Message", "Autopilot:%-4s Plane:%s"),
2363 uih->autopilot ? TR("Message", "On") : TR("Message", "Off"),
2364 planename[uih->fcontext->plane]);
2365 xprint(uih->image, uih->font, 0, statusstart + 7 * h, str, FGCOLOR(uih),
2366 BGCOLOR(uih), 0);
2367 sprintf(str, TR("Message", "incoloring:%s outcoloring:%s"),
2368 incolorname[uih->fcontext->incoloringmode],
2369 outcolorname[uih->fcontext->coloringmode]);
2370 xprint(uih->image, uih->font, 0, statusstart + 8 * h, str, FGCOLOR(uih),
2371 BGCOLOR(uih), 0);
2372 sprintf(str, TR("Message", "zoomspeed:%f"), (float)uih->maxstep * 1000);
2373 xprint(uih->image, uih->font, 0, statusstart + 9 * h, str, FGCOLOR(uih),
2374 BGCOLOR(uih), 0);
2375 if (uih->fcontext->mandelbrot)
2376 strcpy(str, TR("Message", "Parameter:none"));
2377 else
2378 sprintf(str, TR("Message", "Parameter:[%f,%f]"),
2379 (float)uih->fcontext->pre, (float)uih->fcontext->pim);
2380 xprint(uih->image, uih->font, 0, statusstart + 10 * h, str, FGCOLOR(uih),
2381 BGCOLOR(uih), 0);
2382 #ifdef MEMCHECK
2383 {
2384 struct mallinfo i = mallinfo();
2385 sprintf(str, "Allocated arena:%i Wasted:%i %i", i.arena, i.ordblks,
2386 i.fordblks);
2387 xprint(uih->image, uih->font, 0, statusstart + 11 * h, str,
2388 FGCOLOR(uih), BGCOLOR(uih), 0);
2389 sprintf(str, "Mmaped blocks%i Mmaped area:%i keep:%i", i.hblks,
2390 i.hblkhd, i.keepcost);
2391 xprint(uih->image, uih->font, 0, statusstart + 12 * h, str,
2392 FGCOLOR(uih), BGCOLOR(uih), 0);
2393 }
2394 #endif
2395 }
2396
uih_status(uih_context * uih)2397 void uih_status(uih_context *uih)
2398 {
2399 if (statuswindow == NULL) {
2400 statuswindow =
2401 uih_registerw(uih, uih_statuspos, uih_drawstatus, NULL, 0);
2402 } else {
2403 uih_removew(uih, statuswindow);
2404 statuswindow = NULL;
2405 }
2406 uih_updatemenus(uih, "status");
2407 uih_updatemenus(uih, "animministatus");
2408 uih_updatestarts(uih);
2409 }
2410
uih_statusenabled(uih_context *)2411 int uih_statusenabled(uih_context * /*uih*/) { return (statuswindow != NULL); }
2412
uih_ministatuspos(uih_context * uih,int * x,int * y,int * w,int * h,void *)2413 static void uih_ministatuspos(uih_context *uih, int *x, int *y, int *w, int *h,
2414 void * /*data*/)
2415 {
2416 *x = 0;
2417 *y = ministatusstart;
2418 *w = uih->image->width;
2419 *h = xtextheight(uih->image, uih->font);
2420 }
2421
uih_drawministatus(uih_context * uih,void *)2422 static void uih_drawministatus(uih_context *uih, void * /*data*/)
2423 {
2424 xprint(uih->image, uih->font, 0, ministatusstart, statustext, FGCOLOR(uih),
2425 BGCOLOR(uih), 0);
2426 }
2427
uih_ministatus(uih_context * uih)2428 void uih_ministatus(uih_context *uih)
2429 {
2430 if (ministatuswindow == NULL) {
2431 ministatuswindow =
2432 uih_registerw(uih, uih_ministatuspos, uih_drawministatus, NULL, 0);
2433 } else {
2434 uih_removew(uih, ministatuswindow);
2435 ministatuswindow = NULL;
2436 }
2437 uih_updatestarts(uih);
2438 uih_updatemenus(uih, "ministatus");
2439 uih_updatemenus(uih, "animministatus");
2440 }
2441
uih_ministatusenabled(uih_context *)2442 int uih_ministatusenabled(uih_context * /*uih*/)
2443 {
2444 return (ministatuswindow != NULL);
2445 }
2446
uih_cartesiangridpos(uih_context * uih,int * x,int * y,int * w,int * h,void *)2447 static void uih_cartesiangridpos(uih_context *uih, int *x, int *y, int *w, int *h,
2448 void * /*data*/)
2449 {
2450 *x = 0;
2451 *y = 0;
2452 *w = uih->image->width;
2453 *h = uih->image->height-30; // Leave some padding, FIXME
2454 fflush(stdout);
2455 }
2456
uih_drawcartesiangrid(uih_context * uih,void *)2457 static void uih_drawcartesiangrid(uih_context *uih, void * /*data*/)
2458 {
2459 overlayGrid(uih, FGCOLOR(uih));
2460 }
2461
uih_cartesiangrid(uih_context * uih)2462 void uih_cartesiangrid(uih_context *uih)
2463 {
2464 double currzoom =
2465 (uih->fcontext->currentformula->v.rr) / (uih->fcontext->s.rr);
2466
2467 if (cartesiangridwindow == NULL and currzoom < 100000) {
2468 cartesiangridwindow =
2469 uih_registerw(uih, uih_cartesiangridpos, uih_drawcartesiangrid, NULL, 0);
2470 } else {
2471 if(cartesiangridwindow) {
2472 uih_removew(uih, cartesiangridwindow);
2473 cartesiangridwindow = NULL;
2474 } else {
2475 uih_error(uih, "Cartesian Grid not supported on zoom > 100000x");
2476 }
2477 }
2478
2479 uih_updatestarts(uih);
2480 uih_updatemenus(uih, "cartesiangrid");
2481 uih_updatemenus(uih, "animcartesiangrid");
2482 }
2483
uih_cartesiangridenabled(uih_context *)2484 int uih_cartesiangridenabled(uih_context * /*uih*/)
2485 {
2486 return (cartesiangridwindow != NULL);
2487 }
2488