1998-10-20 17:25:25 +04:00
|
|
|
//
|
|
|
|
// Mandelbrot set demo for the Fast Light Tool Kit (FLTK).
|
|
|
|
//
|
2010-11-29 00:06:39 +03:00
|
|
|
// Copyright 1998-2010 by Bill Spitzak and others.
|
1998-10-20 17:25:25 +04:00
|
|
|
//
|
2011-07-19 08:49:30 +04:00
|
|
|
// This library is free software. Distribution and use rights are outlined in
|
|
|
|
// the file "COPYING" which should have been included with this file. If this
|
|
|
|
// file is missing or damaged, see the license at:
|
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// https://www.fltk.org/COPYING.php
|
1998-10-20 17:25:25 +04:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// Please see the following page on how to report bugs and issues:
|
2005-04-16 04:13:17 +04:00
|
|
|
//
|
2020-07-01 19:03:10 +03:00
|
|
|
// https://www.fltk.org/bugs.php
|
1998-10-20 17:25:25 +04:00
|
|
|
//
|
|
|
|
|
2001-12-30 08:16:10 +03:00
|
|
|
#include "mandelbrot_ui.h"
|
1998-10-06 22:21:25 +04:00
|
|
|
#include <FL/fl_draw.H>
|
2010-03-14 21:07:24 +03:00
|
|
|
#include <FL/Fl_Button.H>
|
|
|
|
#include <FL/Fl_Printer.H>
|
1998-10-06 22:21:25 +04:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
Drawing_Window mbrot;
|
|
|
|
Drawing_Window jbrot;
|
|
|
|
|
2008-10-20 00:15:32 +04:00
|
|
|
void idle(void*) {
|
|
|
|
if (!mbrot.d->idle() && !(jbrot.d && jbrot.d->idle())) Fl::remove_idle(idle);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_idle() {
|
2008-10-20 00:15:32 +04:00
|
|
|
Fl::add_idle(idle);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static void window_callback(Fl_Widget*, void*) {exit(0);}
|
|
|
|
|
2010-03-14 21:07:24 +03:00
|
|
|
static void print(Fl_Widget *o, void *data)
|
|
|
|
{
|
|
|
|
Fl_Printer printer;
|
|
|
|
Fl_Window *win = o->window();
|
|
|
|
if(!win->visible()) return;
|
|
|
|
win->make_current();
|
|
|
|
uchar *image_data = fl_read_image(NULL, 0, 0, win->w(), win->h(), 0);
|
|
|
|
if( printer.start_job(1) ) return;
|
|
|
|
if( printer.start_page() ) return;
|
2012-04-05 09:12:30 +04:00
|
|
|
printer.scale(.7f,.7f);
|
2010-03-14 21:07:24 +03:00
|
|
|
fl_draw_image(image_data, 0,0, win->w(), win->h());
|
|
|
|
printer.end_page();
|
|
|
|
delete image_data;
|
|
|
|
printer.end_job();
|
|
|
|
}
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
int main(int argc, char **argv) {
|
1998-10-21 20:35:18 +04:00
|
|
|
mbrot.make_window();
|
2010-03-14 21:07:24 +03:00
|
|
|
mbrot.window->begin();
|
|
|
|
Fl_Button* o = new Fl_Button(0, 0, 0, 0, NULL);
|
|
|
|
o->callback(print,NULL);
|
|
|
|
o->shortcut(FL_CTRL+'p');
|
|
|
|
mbrot.window->end();
|
|
|
|
|
1998-10-06 22:21:25 +04:00
|
|
|
mbrot.d->X = -.75;
|
|
|
|
mbrot.d->scale = 2.5;
|
|
|
|
mbrot.update_label();
|
|
|
|
int i = 0;
|
|
|
|
if (Fl::args(argc,argv,i) < argc) Fl::fatal(Fl::help);
|
|
|
|
Fl::visual(FL_RGB);
|
|
|
|
mbrot.window->callback(window_callback);
|
|
|
|
mbrot.window->show(argc,argv);
|
|
|
|
Fl::run();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Drawing_Window::update_label() {
|
|
|
|
char buffer[128];
|
2022-09-26 17:12:18 +03:00
|
|
|
snprintf(buffer, 128, "%+.10f", d->X); x_input->value(buffer);
|
|
|
|
snprintf(buffer, 128, "%+.10f", d->Y); y_input->value(buffer);
|
|
|
|
snprintf(buffer, 128, "%.2g", d->scale); w_input->value(buffer);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Drawing_Area::draw() {
|
|
|
|
draw_box();
|
|
|
|
drawn = 0;
|
|
|
|
set_idle();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Drawing_Area::idle() {
|
1999-01-13 18:45:50 +03:00
|
|
|
if (!window()->visible()) return 0;
|
1998-10-06 22:21:25 +04:00
|
|
|
if (drawn < nextline) {
|
|
|
|
window()->make_current();
|
|
|
|
int yy = drawn+y()+4;
|
|
|
|
if (yy >= sy && yy <= sy+sh) erase_box();
|
|
|
|
fl_draw_image_mono(buffer+drawn*W,x()+3,yy,W,1,1,W);
|
|
|
|
drawn++;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (nextline < H) {
|
|
|
|
if (!buffer) buffer = new uchar[W*H];
|
|
|
|
double yy = Y+(H/2-nextline)*scale/W;
|
|
|
|
double yi = yy; if (julia) yy = jY;
|
|
|
|
uchar *p = buffer+nextline*W;
|
|
|
|
for (int xi = 0; xi < W; xi++) {
|
|
|
|
double xx = X+(xi-W/2)*scale/W;
|
|
|
|
double wx = xx; double wy = yi;
|
|
|
|
if (julia) xx = jX;
|
|
|
|
for (int i=0; ; i++) {
|
2020-07-01 19:03:10 +03:00
|
|
|
if (i >= iterations) {*p = 0; break;}
|
|
|
|
double t = wx*wx - wy*wy + xx;
|
|
|
|
wy = 2*wx*wy + yy;
|
|
|
|
wx = t;
|
|
|
|
if (wx*wx + wy*wy > 4) {
|
|
|
|
wx = t = 1-double(i)/(1<<10);
|
|
|
|
if (t <= 0) t = 0; else for (i=brightness; i--;) t*=wx;
|
|
|
|
*p = 255-int(254*t);
|
|
|
|
break;
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
nextline++;
|
|
|
|
return nextline < H;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Drawing_Area::erase_box() {
|
|
|
|
window()->make_current();
|
|
|
|
fl_overlay_clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
int Drawing_Area::handle(int event) {
|
|
|
|
static int ix, iy;
|
|
|
|
static int dragged;
|
|
|
|
static int button;
|
|
|
|
int x2,y2;
|
|
|
|
switch (event) {
|
|
|
|
case FL_PUSH:
|
|
|
|
erase_box();
|
|
|
|
ix = Fl::event_x(); if (ix<x()) ix=x(); if (ix>=x()+w()) ix=x()+w()-1;
|
|
|
|
iy = Fl::event_y(); if (iy<y()) iy=y(); if (iy>=y()+h()) iy=y()+h()-1;
|
|
|
|
dragged = 0;
|
|
|
|
button = Fl::event_button();
|
|
|
|
return 1;
|
|
|
|
case FL_DRAG:
|
|
|
|
dragged = 1;
|
|
|
|
erase_box();
|
|
|
|
x2 = Fl::event_x(); if (x2<x()) x2=x(); if (x2>=x()+w()) x2=x()+w()-1;
|
|
|
|
y2 = Fl::event_y(); if (y2<y()) y2=y(); if (y2>=y()+h()) y2=y()+h()-1;
|
|
|
|
if (button != 1) {ix = x2; iy = y2; return 1;}
|
|
|
|
if (ix < x2) {sx = ix; sw = x2-ix;} else {sx = x2; sw = ix-x2;}
|
|
|
|
if (iy < y2) {sy = iy; sh = y2-iy;} else {sy = y2; sh = iy-y2;}
|
|
|
|
window()->make_current();
|
|
|
|
fl_overlay_rect(sx,sy,sw,sh);
|
|
|
|
return 1;
|
|
|
|
case FL_RELEASE:
|
|
|
|
if (button == 1) {
|
|
|
|
erase_box();
|
|
|
|
if (dragged && sw > 3 && sh > 3) {
|
2020-07-01 19:03:10 +03:00
|
|
|
X = X + (sx+sw/2-x()-W/2)*scale/W;
|
|
|
|
Y = Y + (-sy-sh/2+y()+H/2)*scale/W;
|
|
|
|
scale = sw*scale/W;
|
1998-10-06 22:21:25 +04:00
|
|
|
} else if (!dragged) {
|
2020-07-01 19:03:10 +03:00
|
|
|
scale = 2*scale;
|
|
|
|
if (julia) {
|
|
|
|
if (scale >= 4) {
|
|
|
|
scale = 4;
|
|
|
|
X = Y = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (scale >= 2.5) {
|
|
|
|
scale = 2.5;
|
|
|
|
X = -.75;
|
|
|
|
Y = 0;
|
|
|
|
}
|
|
|
|
}
|
1998-10-06 22:21:25 +04:00
|
|
|
} else return 1;
|
|
|
|
((Drawing_Window*)(user_data()))->update_label();
|
|
|
|
new_display();
|
|
|
|
} else if (!julia) {
|
|
|
|
if (!jbrot.d) {
|
2020-07-01 19:03:10 +03:00
|
|
|
jbrot.make_window();
|
|
|
|
jbrot.d->julia = 1;
|
|
|
|
jbrot.d->X = 0;
|
|
|
|
jbrot.d->Y = 0;
|
|
|
|
jbrot.d->scale = 4;
|
|
|
|
jbrot.update_label();
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|
|
|
|
jbrot.d->jX = X + (ix-x()-W/2)*scale/W;
|
|
|
|
jbrot.d->jY = Y + (H/2-iy+y())*scale/W;
|
2001-04-13 23:07:40 +04:00
|
|
|
static char s[128];
|
2022-09-26 17:12:18 +03:00
|
|
|
snprintf(s, 128, "Julia %.7f %.7f",jbrot.d->jX,jbrot.d->jY);
|
2001-04-13 23:07:40 +04:00
|
|
|
jbrot.window->label(s);
|
1998-10-06 22:21:25 +04:00
|
|
|
jbrot.window->show();
|
|
|
|
jbrot.d->new_display();
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Drawing_Area::new_display() {
|
|
|
|
drawn = nextline = 0;
|
|
|
|
set_idle();
|
|
|
|
}
|
|
|
|
|
2001-04-13 23:07:40 +04:00
|
|
|
void Drawing_Area::resize(int XX,int YY,int WW,int HH) {
|
|
|
|
if (WW != w() || HH != h()) {
|
|
|
|
W = WW-6;
|
|
|
|
H = HH-8;
|
1998-10-06 22:21:25 +04:00
|
|
|
if (buffer) {delete[] buffer; buffer = 0; new_display();}
|
|
|
|
}
|
2001-04-13 23:07:40 +04:00
|
|
|
Fl_Box::resize(XX,YY,WW,HH);
|
1998-10-06 22:21:25 +04:00
|
|
|
}
|