PageRenderTime 47ms CodeModel.GetById 5ms RepoModel.GetById 0ms app.codeStats 0ms

/appl/wm/mand.b

https://bitbucket.org/floren/inferno/
Brainfuck | 860 lines | 783 code | 77 blank | 0 comment | 226 complexity | 72e80b70f227ef773fa0fa3f067d4d42 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. implement Mand;
  2. #
  3. # Copyright Š 2000 Vita Nuova Limited. All rights reserved.
  4. #
  5. # mandelbrot/julia fractal browser:
  6. # button 1 - drag a rectangle to zoom into
  7. # button 2 - (from mandel only) show julia at point
  8. # button 3 - zoom out
  9. include "sys.m";
  10. sys : Sys;
  11. include "draw.m";
  12. draw : Draw;
  13. Point, Rect, Image, Context, Screen, Display : import draw;
  14. include "tk.m";
  15. tk: Tk;
  16. include "tkclient.m";
  17. tkclient: Tkclient;
  18. Mand : module
  19. {
  20. init : fn(nil : ref Context, argv : list of string);
  21. };
  22. colours: array of ref Image;
  23. stderr : ref Sys->FD;
  24. FIX: type big;
  25. Calc: adt {
  26. xr, yr: array of FIX;
  27. parx, pary: FIX;
  28. # column order
  29. dispbase: array of COL; # auxiliary display and border
  30. imgch: chan of (ref Image, Rect);
  31. img: ref Image;
  32. maxx, maxy, supx, supy: int;
  33. disp: int; # origin of auxiliary display
  34. morj : int;
  35. winr: Rect;
  36. kdivisor: int;
  37. pointsdone: int;
  38. };
  39. # BASE, LIMIT, MAXCOUNT, MINDELTA may be varied
  40. #
  41. # calls with 256X128 on initial set
  42. # ---------------------------------
  43. # crawl 58 (5% of time)
  44. # fillline 894 (6% of time)
  45. # isblank 5012 (0% of time)
  46. # mcount 6928 (55% of time)
  47. # getcolour 52942 (11% of time)
  48. # displayset 1 (15% of time)
  49. #
  50. WHITE : con 16r0;
  51. BLACK : con 16rff;
  52. COL : type byte;
  53. BASE : con 60; # 28
  54. HBASE : con (BASE/2);
  55. SCALE : con (big 1<<BASE);
  56. TWO : con (big 1<<(BASE+1));
  57. FOUR : con (big 1<<(BASE+2));
  58. NEG : con (~((big 1<<(32-HBASE))-big 1));
  59. MINDELTA : con (big 1<<(HBASE-1)); # (1<<(HBASE-2))
  60. SCHEDCOUNT: con 100;
  61. BLANK : con 0; # blank pixel
  62. BORDER : con 255; # border pixel
  63. LIMIT : con 4; # 4 or 5
  64. # pointcolour() returns values in the range 1..MAXCOUNT+1
  65. # these must not clash with 0 or 255
  66. # hence 0 <= MAXCOUNT <= 253
  67. #
  68. MAXCOUNT : con 253; # 92 64
  69. # colour cube
  70. R, G, B : int;
  71. # initial width and height
  72. WIDTH: con 400;
  73. HEIGHT: con 400;
  74. Fracpoint: adt {
  75. x, y: real;
  76. };
  77. Fracrect: adt {
  78. min, max: Fracpoint;
  79. dx: fn(r: self Fracrect): real;
  80. dy: fn(r: self Fracrect): real;
  81. };
  82. Params: adt {
  83. r: Fracrect;
  84. p: Fracpoint;
  85. m: int;
  86. kdivisor: int;
  87. fill: int;
  88. };
  89. Usercmd: adt {
  90. pick {
  91. Zoomin =>
  92. r: Rect;
  93. Julia =>
  94. p: Point;
  95. Zoomout or
  96. Restart =>
  97. # nothing
  98. }
  99. };
  100. badmod(mod: string)
  101. {
  102. sys->fprint(stderr, "mand: cannot load %s: %r\n", mod);
  103. raise "fail:bad module";
  104. }
  105. win_config := array[] of {
  106. "frame .f",
  107. "label .f.dl -text Depth",
  108. "entry .f.depth",
  109. ".f.depth insert 0 1",
  110. "checkbutton .f.fill -text {Fill} -command {send cmd fillchanged} -variable fill",
  111. ".f.fill select",
  112. "pack .f.dl -side left",
  113. "pack .f.fill -side right",
  114. "pack .f.depth -side top -fill x",
  115. "frame .c -bd 3 -relief sunken -width " + string WIDTH + " -height " + string HEIGHT,
  116. "pack .f -side top -fill x",
  117. "pack .c -side bottom -fill both -expand 1",
  118. "pack propagate . 0",
  119. "bind .c <Button-1> {send cmd b1 %x %y}",
  120. "bind .c <ButtonRelease-2> {send cmd b2 %x %y}",
  121. "bind .c <ButtonRelease-1> {send cmd b1r %x %y}",
  122. "bind .c <ButtonRelease-3> {send cmd b3 %x %y}",
  123. "bind .f.depth <Key-\n> {send cmd setkdivisor}",
  124. "update",
  125. };
  126. mouseproc(win: ref Tk->Toplevel)
  127. {
  128. for(;;)
  129. tk->pointer(win, *<-win.ctxt.ptr);
  130. }
  131. init(ctxt: ref Context, argv : list of string)
  132. {
  133. sys = load Sys Sys->PATH;
  134. stderr = sys->fildes(2);
  135. draw = load Draw Draw->PATH;
  136. tk = load Tk Tk->PATH;
  137. tkclient = load Tkclient Tkclient->PATH;
  138. if (tkclient == nil) badmod(Tkclient->PATH);
  139. tkclient->init();
  140. if (ctxt == nil)
  141. ctxt = tkclient->makedrawcontext();
  142. (win, wmcmd) := tkclient->toplevel(ctxt, "", "Fractals", Tkclient->Appl);
  143. sys->pctl(Sys->NEWPGRP, nil);
  144. cmdch := chan of string;
  145. tk->namechan(win, cmdch, "cmd");
  146. for (i := 0; i < len win_config; i++)
  147. cmd(win, win_config[i]);
  148. tkclient->onscreen(win, nil);
  149. tkclient->startinput(win, "kbd"::"ptr"::nil);
  150. fittoscreen(win);
  151. cmd(win, "update");
  152. spawn mouseproc(win);
  153. R = G = B = 6;
  154. argv = tl argv;
  155. if (argv != nil) { (R, argv) = (int hd argv, tl argv); if (R <= 0) R = 1; }
  156. if (argv != nil) { (G, argv) = (int hd argv, tl argv); if (G <= 0) G = 1; }
  157. if (argv != nil) { (B, argv) = (int hd argv, tl argv); if (B <= 0) B = 1; }
  158. colours = array[256] of ref Image;
  159. for (i = 0; i < len colours; i++)
  160. # colours[i] = ctxt.display.color(i);
  161. colours[i] = ctxt.display.rgb(col(i/(G*B), R),
  162. col(i/(1*B), G),
  163. col(i/(1*1), B));
  164. canvr := canvposn(win);
  165. specr := Fracrect((-2.0, -1.5), (1.0, 1.5));
  166. p := Params(
  167. correctratio(specr, canvr),
  168. (0.0, 0.0),
  169. 1, # m
  170. 1, # kdivisor
  171. int cmd(win, "variable fill")
  172. );
  173. pid := -1;
  174. sync := chan of int;
  175. imgch := chan of (ref Image, Rect);
  176. spawn docalculate(sync, p, imgch);
  177. pid = <-sync;
  178. imgch <-= (win.image, canvr);
  179. stack: list of (Fracrect, Params);
  180. for(;;){
  181. restart := 0;
  182. alt {
  183. s := <-win.ctxt.kbd =>
  184. tk->keyboard(win, s);
  185. c := <-win.ctxt.ctl or
  186. c = <-win.wreq or
  187. c = <-wmcmd =>
  188. if(c[0] == '!'){
  189. if(pid != -1)
  190. restart = winreq(win, c, imgch, sync);
  191. else
  192. restart = winreq(win, c, nil, nil);
  193. }else{
  194. tkclient->wmctl(win, c);
  195. if(c == "task" && pid != -1){
  196. kill(pid);
  197. pid = -1;
  198. }
  199. }
  200. press := <-cmdch =>
  201. (nil, toks) := sys->tokenize(press, " ");
  202. ucmd: ref Usercmd = nil;
  203. case hd toks {
  204. "start" =>
  205. ucmd = ref Usercmd.Restart;
  206. "b1" or "b2" or "b3" =>
  207. #cmd(win, "grab set .c");
  208. #fiximage(win);
  209. ucmd = trackmouse(win, cmdch, hd toks, Point(int hd tl toks, int hd tl tl toks));
  210. #cmd(win, "grab release .c");
  211. "fillchanged" =>
  212. p.fill = int cmd(win, "variable fill");
  213. ucmd = ref Usercmd.Restart;
  214. "setkdivisor" =>
  215. p.kdivisor = int cmd(win, ".f.depth get");
  216. if (p.kdivisor < 1)
  217. p.kdivisor = 1;
  218. ucmd = ref Usercmd.Restart;
  219. }
  220. if (ucmd != nil) {
  221. pick u := ucmd {
  222. Zoomin =>
  223. # sys->print("zoomin to %s\n", r2s(u.r));
  224. if (u.r.dx() > 0 && u.r.dy() > 0) {
  225. stack = (specr, p) :: stack;
  226. specr.min = pt2real(u.r.min, win, p.r);
  227. specr.max = pt2real(u.r.max, win, p.r);
  228. (specr.min.y, specr.max.y) = (specr.max.y, specr.min.y); # canonicalise
  229. restart = 1;
  230. }
  231. Zoomout =>
  232. if (stack != nil) {
  233. ((specr, p), stack) = (hd stack, tl stack);
  234. cmd(win, ".f.depth delete 0 end");
  235. cmd(win, ".f.depth insert 0 " + string p.kdivisor);
  236. if (p.fill)
  237. cmd(win, ".f.fill select");
  238. else
  239. cmd(win, ".f.fill deselect");
  240. cmd(win, "update");
  241. restart = 1;
  242. }
  243. Julia =>
  244. # pt := pt2real(u.p, win, p.r);
  245. if (p.m) {
  246. stack = (specr, p) :: stack;
  247. p.p = pt2real(u.p, win, p.r);
  248. specr = ((-2.0, -1.5), (1.0, 1.5));
  249. p.m = 0;
  250. restart = 1;
  251. }
  252. Restart =>
  253. restart = 1;
  254. }
  255. }
  256. <-sync =>
  257. win.image.flush(Draw->Flushon);
  258. pid = -1;
  259. }
  260. if (restart) {
  261. if (pid != -1)
  262. kill(pid);
  263. win.image.flush(Draw->Flushoff);
  264. wr := canvposn(win);
  265. if(!isempty(wr)){
  266. p.r = correctratio(specr, wr);
  267. sync = chan of int;
  268. spawn docalculate(sync, p, imgch);
  269. pid = <-sync;
  270. imgch <-= (win.image, wr);
  271. }
  272. }
  273. }
  274. }
  275. winreq(win: ref Tk->Toplevel, c: string, imgch: chan of (ref Image, Rect), terminated: chan of int): int
  276. {
  277. oldimage := win.image;
  278. if (imgch != nil) {
  279. # halt calculation process
  280. alt {
  281. imgch <-= (nil, ((0,0), (0,0))) =>;
  282. <-terminated =>
  283. imgch = nil;
  284. }
  285. }
  286. tkclient->wmctl(win, c);
  287. if(win.image != oldimage)
  288. return 1;
  289. if(imgch != nil)
  290. imgch <-= (win.image, canvposn(win));
  291. return 0;
  292. }
  293. correctratio(r: Fracrect, wr: Rect): Fracrect
  294. {
  295. # make sure calculation rectangle is in
  296. # the same ratio as bitmap (also make sure that
  297. # calculated area always includes desired area)
  298. if(isempty(wr))
  299. return ((0.0,0.0), (0.0,0.0));
  300. (btall, atall) := (real wr.dy() / real wr.dx(), r.dy() / r.dx());
  301. if (btall > atall) {
  302. # bitmap is taller than area, so expand area vertically
  303. excess := r.dx()*btall - r.dy();
  304. r.min.y -= excess / 2.0;
  305. r.max.y += excess / 2.0;
  306. } else {
  307. # area is taller than bitmap, so expand area horizontally
  308. excess := r.dy()/btall - r.dx();
  309. r.min.x -= excess / 2.0;
  310. r.max.x += excess / 2.0;
  311. }
  312. return r;
  313. }
  314. pt2real(pt: Point, win: ref Tk->Toplevel, r: Fracrect): Fracpoint
  315. {
  316. sz := Point(int cmd(win, ".c cget -actwidth"), int cmd(win, ".c cget -actheight"));
  317. return (real pt.x / real sz.x * (r.max.x- r.min.x) + r.min.x,
  318. real (sz.y - pt.y) / real sz.y * (r.max.y - r.min.y) + r.min.y);
  319. }
  320. pt2s(pt: Point): string
  321. {
  322. return string pt.x + " " + string pt.y;
  323. }
  324. r2s(r: Rect): string
  325. {
  326. return pt2s(r.min) + " " + pt2s(r.max);
  327. }
  328. trackmouse(win: ref Tk->Toplevel, cmdch: chan of string, but: string, p: Point): ref Usercmd
  329. {
  330. case but {
  331. "b1" =>
  332. cr := canvposn(win);
  333. display := win.image.display;
  334. save := display.newimage(cr, win.image.chans, 0, Draw->Nofill);
  335. save.draw(cr, win.image, nil, cr.min);
  336. oclip := win.image.clipr;
  337. win.image.clipr = cr;
  338. p = p.add(cr.min);
  339. r := Rect(p, p);
  340. win.image.border(r, 1, display.white, (0, 0));
  341. win.image.flush(Draw->Flushnow);
  342. do {
  343. but = <-cmdch;
  344. (nil, toks) := sys->tokenize(but, " ");
  345. but = hd toks;
  346. if(but == "b1"){
  347. xr := r.canon();
  348. win.image.draw(xr, save, nil, xr.min);
  349. (r.max.x, r.max.y) = (int hd tl toks + cr.min.x, int hd tl tl toks + cr.min.y);
  350. win.image.border(r.canon(), 1, display.white, (0, 0));
  351. win.image.flush(Draw->Flushnow);
  352. }
  353. } while (but != "b1r");
  354. r = r.canon();
  355. win.image.draw(r, save, nil, r.min);
  356. win.image.clipr = oclip;
  357. r = r.subpt(cr.min);
  358. return ref Usercmd.Zoomin(r);
  359. "b2" =>
  360. return ref Usercmd.Julia(p);
  361. "b3" =>
  362. return ref Usercmd.Zoomout;
  363. }
  364. return nil;
  365. }
  366. poll(calc: ref Calc)
  367. {
  368. calc.img.flush(Draw->Flushnow);
  369. alt {
  370. <-calc.imgch =>
  371. calc.img = nil;
  372. (calc.img, calc.winr) = <-calc.imgch;
  373. * =>;
  374. }
  375. }
  376. docalculate(sync: chan of int, p: Params, imgch: chan of (ref Image, Rect))
  377. {
  378. if (p.m)
  379. ; # sys->print("mandel [[%g,%g],[%g,%g]]\n", r.min.x, r.min.y, r.max.x, r.max.y);
  380. else
  381. ; # sys->print("julia [[%g,%g],[%g,%g]] [%g,%g]\n", r.min.x, r.min.y, r.max.x, r.max.y, p.p.x, p.p.y);
  382. sync <-= sys->pctl(0, nil);
  383. calculate(p, imgch);
  384. sync <-= 0;
  385. }
  386. canvposn(win: ref Tk->Toplevel): Rect
  387. {
  388. return tk->rect(win, ".c", Tk->Local);
  389. }
  390. isempty(r: Rect): int
  391. {
  392. return r.dx() <= 0 || r.dy() <= 0;
  393. }
  394. calculate(p: Params, imgch: chan of (ref Image, Rect))
  395. {
  396. calc := ref Calc;
  397. (calc.img, calc.winr) = <-imgch;
  398. r := calc.winr;
  399. calc.maxx = r.dx();
  400. calc.maxy = r.dy();
  401. calc.supx = calc.maxx + 2;
  402. calc.supy = calc.maxy + 2;
  403. calc.imgch = imgch;
  404. calc.xr = array[calc.maxx] of FIX;
  405. calc.yr = array[calc.maxy] of FIX;
  406. calc.morj = p.m;
  407. initr(calc, p);
  408. calc.img.drawop(r, calc.img.display.white, nil, (0,0), Draw->S);
  409. if (p.fill) {
  410. calc.dispbase = array[calc.supx*calc.supy] of COL; # auxiliary display and border
  411. calc.disp = calc.maxy + 3;
  412. setdisp(calc);
  413. displayset(calc);
  414. } else {
  415. for (x := 0; x < calc.maxx; x++) {
  416. for (y := 0; y < calc.maxy; y++)
  417. point(calc, calc.img, (x, y), pointcolour(calc, x, y));
  418. }
  419. }
  420. }
  421. setdisp(calc: ref Calc)
  422. {
  423. d : int;
  424. i : int;
  425. for (i = 0; i < calc.supx*calc.supy; i++)
  426. calc.dispbase[i] = byte BLANK;
  427. i = 0;
  428. for (d = 0; i < calc.supx; d += calc.supy) {
  429. calc.dispbase[d] = byte BORDER;
  430. i++;
  431. }
  432. i = 0;
  433. for (d = 0; i < calc.supy; d++) {
  434. calc.dispbase[d] = byte BORDER;
  435. i++;
  436. }
  437. i = 0;
  438. for (d = 0+calc.supx*calc.supy-1; i < calc.supx; d -= calc.supy) {
  439. calc.dispbase[d] = byte BORDER;
  440. i++;
  441. }
  442. i = 0;
  443. for (d = 0+calc.supx*calc.supy-1; i < calc.supy; d--) {
  444. calc.dispbase[d] = byte BORDER;
  445. i++;
  446. }
  447. }
  448. initr(calc: ref Calc, p: Params): int
  449. {
  450. r := p.r;
  451. dp := real2fix((r.max.x-r.min.x)/(real calc.maxx));
  452. dq := real2fix((r.max.y-r.min.y)/(real calc.maxy));
  453. calc.xr[0] = real2fix(r.min.x)-(big calc.maxx*dp-(real2fix(r.max.x)-real2fix(r.min.x)))/big 2;
  454. for (x := 1; x < calc.maxx; x++)
  455. calc.xr[x] = calc.xr[x-1] + dp;
  456. calc.yr[0] = real2fix(r.max.y)+(big calc.maxy*dq-(real2fix(r.max.y)-real2fix(r.min.y)))/big 2;
  457. for (y := 1; y < calc.maxy; y++)
  458. calc.yr[y] = calc.yr[y-1] - dq;
  459. calc.parx = real2fix(p.p.x);
  460. calc.pary = real2fix(p.p.y);
  461. calc.kdivisor = p.kdivisor;
  462. calc.pointsdone = 0;
  463. return dp >= MINDELTA && dq >= MINDELTA;
  464. }
  465. fillline(calc: ref Calc, x, y, d, dir, dird, col: int)
  466. {
  467. x0 := x;
  468. while (calc.dispbase[d] == byte BLANK) {
  469. calc.dispbase[d] = byte col;
  470. x -= dir;
  471. d -= dird;
  472. }
  473. if (0 && pointcolour(calc, (x0+x+dir)/2, y) != col) { # midpoint of line (island code)
  474. # island - undo colouring or do properly
  475. do {
  476. d += dird;
  477. x += dir;
  478. # *d = BLANK;
  479. calc.dispbase[d] = byte pointcolour(calc, x, y);
  480. point(calc, calc.img, (x, y), int calc.dispbase[d]);
  481. } while (x != x0);
  482. return; # abort crawl ?
  483. }
  484. horizline(calc, calc.img, x0, x, y, col);
  485. }
  486. crawlt(calc: ref Calc, x, y, d, col: int)
  487. {
  488. yinc, dyinc : int;
  489. firstd := d;
  490. xinc := 1;
  491. dxinc := calc.supy;
  492. for (;;) {
  493. if (getcolour(calc, x+xinc, y, d+dxinc) == col) {
  494. x += xinc;
  495. d += dxinc;
  496. yinc = -xinc;
  497. dyinc = -dxinc;
  498. # if (isblank(x+xinc, y, d+dxinc))
  499. if (calc.dispbase[d+dxinc] == byte BLANK)
  500. fillline(calc, x+xinc, y, d+dxinc, yinc, dyinc, col);
  501. if (d == firstd)
  502. break;
  503. }
  504. else {
  505. yinc = xinc;
  506. dyinc = dxinc;
  507. }
  508. if (getcolour(calc, x, y+yinc, d+yinc) == col) {
  509. y += yinc;
  510. d += yinc;
  511. xinc = yinc;
  512. dxinc = dyinc;
  513. # if (isblank(x-xinc, y, d-dxinc))
  514. if (calc.dispbase[d-dxinc] == byte BLANK)
  515. fillline(calc, x-xinc, y, d-dxinc, yinc, dyinc, col);
  516. if (d == firstd)
  517. break;
  518. }
  519. else {
  520. xinc = -yinc;
  521. dxinc = -dyinc;
  522. }
  523. }
  524. }
  525. # spurious lines problem - disallow all acw paths
  526. #
  527. # 43--------->
  528. # 12--------->
  529. #
  530. # 654------------>
  531. # 7 3------------>
  532. # 812------------>
  533. #
  534. # Given a closed curve completely described by unit movements LRUD (left,
  535. # right, up, and down), calculate the enclosed area. The description
  536. # may be cw or acw and of arbitrary shape.
  537. #
  538. # Based on Green's Theorem :- area = integral ydx
  539. # C
  540. # area = 0;
  541. # count = ARBITRARY_VALUE;
  542. # while( moves_are_left() ){
  543. # move = next_move();
  544. # switch(move){
  545. # case L:
  546. # area -= count;
  547. # break;
  548. # case R:
  549. # area += count;
  550. # break;
  551. # case U:
  552. # count++;
  553. # break;
  554. # case D:
  555. # count--;
  556. # break;
  557. # }
  558. # area = abs(area);
  559. crawlf(calc: ref Calc, x, y, d, col: int)
  560. {
  561. xinc, yinc, dxinc, dyinc : int;
  562. firstx, firsty : int;
  563. firstd : int;
  564. area := 0;
  565. count := 0;
  566. firstx = x;
  567. firsty = y;
  568. firstd = d;
  569. xinc = 1;
  570. dxinc = calc.supy;
  571. # acw on success, cw on failure
  572. for (;;) {
  573. if (getcolour(calc, x+xinc, y, d+dxinc) == col) {
  574. x += xinc;
  575. d += dxinc;
  576. yinc = -xinc;
  577. dyinc = -dxinc;
  578. area += xinc*count;
  579. if (d == firstd)
  580. break;
  581. } else {
  582. yinc = xinc;
  583. dyinc = dxinc;
  584. }
  585. if (getcolour(calc, x, y+yinc, d+yinc) == col) {
  586. y += yinc;
  587. d += yinc;
  588. xinc = yinc;
  589. dxinc = dyinc;
  590. count -= yinc;
  591. if (d == firstd)
  592. break;
  593. } else {
  594. xinc = -yinc;
  595. dxinc = -dyinc;
  596. }
  597. }
  598. if (area > 0) # cw
  599. crawlt(calc, firstx, firsty, firstd, col);
  600. }
  601. displayset(calc: ref Calc)
  602. {
  603. edge : int;
  604. last := BLANK;
  605. d := calc.disp;
  606. for (x := 0; x < calc.maxx; x++) {
  607. for (y := 0; y < calc.maxy; y++) {
  608. col := calc.dispbase[d];
  609. if (col == byte BLANK) {
  610. col = calc.dispbase[d] = byte pointcolour(calc, x, y);
  611. point(calc, calc.img, (x, y), int col);
  612. if (col == byte last)
  613. edge++;
  614. else {
  615. last = int col;
  616. edge = 0;
  617. }
  618. if (edge >= LIMIT) {
  619. crawlf(calc, x, y-edge, d-edge, last);
  620. # prevent further crawlf()
  621. last = BLANK;
  622. }
  623. }
  624. else {
  625. if (col == byte last)
  626. edge++;
  627. else {
  628. last = int col;
  629. edge = 0;
  630. }
  631. }
  632. d++;
  633. }
  634. last = BLANK;
  635. d += 2;
  636. }
  637. }
  638. pointcolour(calc: ref Calc, x, y: int) : int
  639. {
  640. if (++calc.pointsdone >= SCHEDCOUNT) {
  641. calc.pointsdone = 0;
  642. sys->sleep(0);
  643. poll(calc);
  644. }
  645. if (calc.morj)
  646. return mcount(calc, x, y) + 1;
  647. else
  648. return jcount(calc, x, y) + 1;
  649. }
  650. mcount(calc: ref Calc, x_coord, y_coord: int): int
  651. {
  652. (p, q) := (calc.xr[x_coord], calc.yr[y_coord]);
  653. (x, y) := (calc.parx, calc.pary);
  654. k := 0;
  655. maxcount := MAXCOUNT * calc.kdivisor;
  656. while (k < maxcount) {
  657. if (x >= TWO || y >= TWO || x <= -TWO || y <= -TWO)
  658. break;
  659. if (0) {
  660. # x = (x < 0) ? (x>>HBASE)|NEG : x>>HBASE;
  661. # y = (y < 0) ? (y>>HBASE)|NEG : y>>HBASE;
  662. }
  663. x >>= HBASE;
  664. y >>= HBASE;
  665. t := y*y;
  666. y = big 2*x*y+q; # possible unserious overflow when BASE == 28
  667. x *= x;
  668. if (x+t >= FOUR)
  669. break;
  670. x -= t-p;
  671. k++;
  672. }
  673. return k / calc.kdivisor;
  674. }
  675. jcount(calc: ref Calc, x_coord, y_coord: int): int
  676. {
  677. (x, y) := (calc.xr[x_coord], calc.yr[y_coord]);
  678. (p, q) := (calc.parx, calc.pary);
  679. k := 0;
  680. maxcount := MAXCOUNT * calc.kdivisor;
  681. while (k < maxcount) {
  682. if (x >= TWO || y >= TWO || x <= -TWO || y <= -TWO)
  683. break;
  684. if (0) {
  685. # x = (x < 0) ? (x>>HBASE)|NEG : x>>HBASE;
  686. # y = (y < 0) ? (y>>HBASE)|NEG : y>>HBASE;
  687. }
  688. x >>= HBASE;
  689. y >>= HBASE;
  690. t := y*y;
  691. y = big 2*x*y+q; # possible unserious overflow when BASE == 28
  692. x *= x;
  693. if (x+t >= FOUR)
  694. break;
  695. x -= t-p;
  696. k++;
  697. }
  698. return k / calc.kdivisor;
  699. }
  700. getcolour(calc: ref Calc, x, y, d: int): int
  701. {
  702. if (calc.dispbase[d] == byte BLANK) {
  703. calc.dispbase[d] = byte pointcolour(calc, x, y);
  704. point(calc, calc.img, (x, y), int calc.dispbase[d]);
  705. }
  706. return int calc.dispbase[d];
  707. }
  708. point(calc: ref Calc, d: ref Image, p: Point, col: int)
  709. {
  710. d.draw(Rect(p, p.add((1,1))).addpt(calc.winr.min), colours[col], nil, (0,0));
  711. }
  712. horizline(calc: ref Calc, d: ref Image, x0, x1, y: int, col: int)
  713. {
  714. if (x0 < x1)
  715. r := Rect((x0, y), (x1, y+1));
  716. else
  717. r = Rect((x1+1, y), (x0+1, y+1));
  718. d.draw(r.addpt(calc.winr.min), colours[col], nil, (0, 0));
  719. # r := Rect((x0, y), (x1, y)).canon();
  720. # r.max = r.max.add((1, 1));
  721. }
  722. Fracrect.dx(r: self Fracrect): real
  723. {
  724. return r.max.x - r.min.x;
  725. }
  726. Fracrect.dy(r: self Fracrect): real
  727. {
  728. return r.max.y - r.min.y;
  729. }
  730. real2fix(x: real): FIX
  731. {
  732. return big (x * real SCALE);
  733. }
  734. cmd(top: ref Tk->Toplevel, s: string): string
  735. {
  736. e := tk->cmd(top, s);
  737. if (e != nil && e[0] == '!')
  738. sys->fprint(stderr, "mand: tk error on '%s': %s\n", s, e);
  739. return e;
  740. }
  741. kill(pid: int): int
  742. {
  743. fd := sys->open("/prog/"+string pid+"/ctl", Sys->OWRITE);
  744. if (fd == nil)
  745. return -1;
  746. if (sys->write(fd, array of byte "kill", 4) != 4)
  747. return -1;
  748. return 0;
  749. }
  750. col(i, r : int) : int
  751. {
  752. if (r == 1)
  753. return 0;
  754. return (255*(i%r))/(r-1);
  755. }
  756. fittoscreen(win: ref Tk->Toplevel)
  757. {
  758. Point: import draw;
  759. if (win.image == nil || win.image.screen == nil)
  760. return;
  761. r := win.image.screen.image.r;
  762. scrsize := Point((r.max.x - r.min.x), (r.max.y - r.min.y));
  763. bd := int cmd(win, ". cget -bd");
  764. winsize := Point(int cmd(win, ". cget -actwidth") + bd * 2, int cmd(win, ". cget -actheight") + bd * 2);
  765. if (winsize.x > scrsize.x)
  766. cmd(win, ". configure -width " + string (scrsize.x - bd * 2));
  767. if (winsize.y > scrsize.y)
  768. cmd(win, ". configure -height " + string (scrsize.y - bd * 2));
  769. actr: Rect;
  770. actr.min = Point(int cmd(win, ". cget -actx"), int cmd(win, ". cget -acty"));
  771. actr.max = actr.min.add((int cmd(win, ". cget -actwidth") + bd*2,
  772. int cmd(win, ". cget -actheight") + bd*2));
  773. (dx, dy) := (actr.dx(), actr.dy());
  774. if (actr.max.x > r.max.x)
  775. (actr.min.x, actr.max.x) = (r.max.x - dx, r.max.x);
  776. if (actr.max.y > r.max.y)
  777. (actr.min.y, actr.max.y) = (r.max.y - dy, r.max.y);
  778. if (actr.min.x < r.min.x)
  779. (actr.min.x, actr.max.x) = (r.min.x, r.min.x + dx);
  780. if (actr.min.y < r.min.y)
  781. (actr.min.y, actr.max.y) = (r.min.y, r.min.y + dy);
  782. cmd(win, ". configure -x " + string actr.min.x + " -y " + string actr.min.y);
  783. }