From ae82157d19f31bf16026ea71f356e24828dab05d Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Sat, 24 Oct 2020 23:27:16 +0200 Subject: [PATCH 1/2] Add interactive mandelbrot example --- .../mandelbrot/mandelbrot-interactive.csn | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 examples/mandelbrot/mandelbrot-interactive.csn diff --git a/examples/mandelbrot/mandelbrot-interactive.csn b/examples/mandelbrot/mandelbrot-interactive.csn new file mode 100644 index 0000000..4c2ab2a --- /dev/null +++ b/examples/mandelbrot/mandelbrot-interactive.csn @@ -0,0 +1,212 @@ +( + (sc-init 1024 768) + (sc-opt SCREEN_AUTOBLIT 0) + (def W 1024) + (def H 768) + (def MAXITER 50) + + ; size of big pixels + (def COL_SKIP 8) + (def ROW_SKIP 8) + + (lds @cout "Interactive Mandelbrot\n") + (lds @cout "----------------------\n") + (lds @cout "Navigate using WASD, zoom using Q/E\n") + (lds @cout "To get a high-res image, stop interacting for while\n") + + (sym asciigr r10) + + (sym mb_x r2) + (sym mb_y r3) + (sym mb_s r4) + (sym mb_row r5) + (sym mb_col_skip r6) + (sym mb_row_skip r7) + + (ld mb_x 0.0) + (ld mb_y 0.0) + (ld mb_s 1.0) + (sym did_change r14) + (sym is_first_render r15) + (ld is_first_render 1) + + ; render row + ; big - is this the first render? if yes, use big pixels + ; col - mb_col_skip column offset + ; px - offset x + ; py - offset y + ; scale - scaling + ; row - row position + (proc render_row big col px py scale row + (sym gradient r9) + (mkbf gradient ( + 0x421e0f 0x19071a 0x09012f 0x040449 0x000764 0x0c2c8a 0x1852b1 0x397dd1 + 0x86b5e5 0xd3ecf8 0xf1e9bf 0xf8c95f 0xffaa00 0xcc8000 0x995700 0x6a3403)) + + (sym x r7) + (sym y r8) + (add y row) + (ld x col) + (:col) + (call pixel x y px py scale) + (sub r0 MAXITER 1) + (rcmp res0 1 r0 + (eq? + (mod r0 res0 16) + (bfrd r0 @gradient r0) + ) + (else? (ld r0 0)) + ) + (cmp big 1) + (j.ne :not_big) + (sc-rect x y COL_SKIP ROW_SKIP r0) + (j :was_big) + (:not_big) + (sc-wr x y r0) + (:was_big) + (add x COL_SKIP) + (cmp x W) + (j.lt :col) + (sc-blit) + (ret)) + + (:slp) + (sc-poll) + ; did_change -- did the user interact during this frame? + (ld did_change 0) + + ; scaled movement speed in r1 + (fdiv r1 0.03 mb_s) + + ; A < + (sc-key r0 KEY_A) + (j.z :a_not_pressed) + (fsub mb_x r1) + (ld did_change 1) + (:a_not_pressed) + + ; W ^ + (sc-key r0 KEY_W) + (j.z :w_not_pressed) + (fsub mb_y r1) + (ld did_change 1) + (:w_not_pressed) + + ; S v + (sc-key r0 KEY_S) + (j.z :s_not_pressed) + (fadd mb_y r1) + (ld did_change 1) + (:s_not_pressed) + + ; D > + (sc-key r0 KEY_D) + (j.z :d_not_pressed) + (fadd mb_x r1) + (ld did_change 1) + (:d_not_pressed) + + ; Q + + (sc-key r0 KEY_Q) + (j.z :q_not_pressed) + (fmul mb_s 1.01) + (ld did_change 1) + (:q_not_pressed) + + ; E - + (sc-key r0 KEY_E) + (j.z :e_not_pressed) + (fdiv mb_s 1.01) + (ld did_change 1) + (:e_not_pressed) + + (cmp did_change 0) + (j.eq :did_not_move) + ; if something changed... + + ; mark this as a first render and reset col_skip and row_skip + (ld is_first_render 1) + (ld mb_col_skip 0) + (ld mb_row_skip 0) + (:did_not_move) + + ; render row mb_row + mb_row_skip + (ld r0 mb_row) + (add r0 mb_row_skip) + (call render_row is_first_render mb_col_skip mb_x mb_y mb_s r0) + + (cmp mb_row H) + (j.ge :render_done) + ; if mb_row < H + (add mb_row ROW_SKIP) + (j :render_not_done) + (:render_done) + ; otherwise, this frame is done + (ld mb_row 0) + (add mb_col_skip 1) + (ld is_first_render 0) + (mod mb_col_skip COL_SKIP) + + ; if mb_col_skip wrapped back to zero increase mb_row_skip + (cmp mb_col_skip 0) + (j.ne :not_col) + (add mb_row_skip 1) + (mod mb_row_skip ROW_SKIP) + (:not_col) + (:render_not_done) + (j :slp) + + (proc pixel xi yi off_x off_y scale + (sym x0 r7) + (sym y0 r8) + (itf x0 xi) + (itf y0 yi) + + ; Scale to the interesting range x -2.5..1 and y -1..1 + (itf r0 W) + (itf r1 H) + + (fdiv x0 r0) + (fmul x0 3.5) + (fsub x0 2.5) + + (fdiv y0 r1) + (fmul y0 2.4) + (fsub y0 1.2) + + (fdiv x0 scale) + (fdiv y0 scale) + (fadd x0 off_x) + (fadd y0 off_y) + + (sym x r5) + (sym y r6) + (ld x 0.0) + (ld y 0.0) + (sym iter r4) + + (:iter) + (cmp iter MAXITER) + (j.eq :end) + (fmul r0 x x) + (fmul r1 y y) + (fadd r2 r1) + (fcmp r2 4.0) + (j.gt :end) + + (fsub r2 r0 r1) + (fadd r2 x0) + + (fmul r0 x y) + (fmul r0 2.0) + (fadd r0 y0) + (ld y r0) + (ld x r2) + (inc iter) + (j :iter) + + (:end) + (ret iter) + ) +) + From e6c8125cfe4be7dcb05a20ed8ec290ece72158a5 Mon Sep 17 00:00:00 2001 From: cpsdqs Date: Sun, 25 Oct 2020 00:10:27 +0200 Subject: [PATCH 2/2] Interactive mandelbrot: use quadtree table for nicer previews --- .../mandelbrot/mandelbrot-interactive.csn | 89 +++++++++++++------ 1 file changed, 60 insertions(+), 29 deletions(-) diff --git a/examples/mandelbrot/mandelbrot-interactive.csn b/examples/mandelbrot/mandelbrot-interactive.csn index 4c2ab2a..cc53e42 100644 --- a/examples/mandelbrot/mandelbrot-interactive.csn +++ b/examples/mandelbrot/mandelbrot-interactive.csn @@ -5,10 +5,6 @@ (def H 768) (def MAXITER 50) - ; size of big pixels - (def COL_SKIP 8) - (def ROW_SKIP 8) - (lds @cout "Interactive Mandelbrot\n") (lds @cout "----------------------\n") (lds @cout "Navigate using WASD, zoom using Q/E\n") @@ -20,8 +16,46 @@ (sym mb_y r3) (sym mb_s r4) (sym mb_row r5) - (sym mb_col_skip r6) - (sym mb_row_skip r7) + + ; index into the skip/size table + (sym mb_skip_index r6) + + ; size of big pixels + (def COL_SKIP 8) + (def ROW_SKIP 8) + ; incrementally renders 1x1, 2x2, 4x4, ... + (def MB_SKIP_TABLE_SIZE 80) + (def MB_SKIP_REPEAT_INDEX 16) + (sym mb_skip_table_x r7) + (sym mb_skip_table_y r8) + (sym mb_size_table r12) + (mkbf mb_skip_table_x ( + 0 4 0 4 2 6 0 2 4 6 2 6 0 2 4 6 + ; 8x8 grid + 1 3 5 7 1 3 5 7 1 3 5 7 1 3 5 7 + 0 2 4 6 0 2 4 6 0 2 4 6 0 2 4 6 + 1 3 5 7 1 3 5 7 1 3 5 7 1 3 5 7 + ; do top left pixels again + 0 2 4 6 0 2 4 6 0 2 4 6 0 2 4 6 + )) + (mkbf mb_skip_table_y ( + 0 0 4 4 0 0 2 2 2 2 4 4 6 6 6 6 + ; 8x8 grid + 0 0 0 0 2 2 2 2 4 4 4 4 6 6 6 6 + 1 1 1 1 3 3 3 3 5 5 5 5 7 7 7 7 + 1 1 1 1 3 3 3 3 5 5 5 5 7 7 7 7 + ; do top left pixels again + 0 0 0 0 2 2 2 2 4 4 4 4 6 6 6 6 + )) + (mkbf mb_size_table ( + 8 4 4 4 2 2 2 2 2 2 2 2 2 2 2 2 + ; 8x8 grid + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + ; do top left pixels again + 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 + )) (ld mb_x 0.0) (ld mb_y 0.0) @@ -31,13 +65,13 @@ (ld is_first_render 1) ; render row - ; big - is this the first render? if yes, use big pixels - ; col - mb_col_skip column offset + ; size - pixel size + ; col - column offset ; px - offset x ; py - offset y ; scale - scaling ; row - row position - (proc render_row big col px py scale row + (proc render_row size col px py scale row (sym gradient r9) (mkbf gradient ( 0x421e0f 0x19071a 0x09012f 0x040449 0x000764 0x0c2c8a 0x1852b1 0x397dd1 @@ -57,13 +91,7 @@ ) (else? (ld r0 0)) ) - (cmp big 1) - (j.ne :not_big) - (sc-rect x y COL_SKIP ROW_SKIP r0) - (j :was_big) - (:not_big) - (sc-wr x y r0) - (:was_big) + (sc-rect x y size size r0) (add x COL_SKIP) (cmp x W) (j.lt :col) @@ -126,14 +154,19 @@ ; mark this as a first render and reset col_skip and row_skip (ld is_first_render 1) - (ld mb_col_skip 0) - (ld mb_row_skip 0) + (ld mb_skip_index 0) (:did_not_move) - ; render row mb_row + mb_row_skip + (sym mb_col_skip r9) + (sym mb_row_skip r11) + (bfrd mb_col_skip @mb_skip_table_x mb_skip_index) + (bfrd mb_row_skip @mb_skip_table_y mb_skip_index) + (bfrd r1 @mb_size_table mb_skip_index) + + ; render row mb_row + row skip (ld r0 mb_row) (add r0 mb_row_skip) - (call render_row is_first_render mb_col_skip mb_x mb_y mb_s r0) + (call render_row r1 mb_col_skip mb_x mb_y mb_s r0) (cmp mb_row H) (j.ge :render_done) @@ -143,16 +176,14 @@ (:render_done) ; otherwise, this frame is done (ld mb_row 0) - (add mb_col_skip 1) + (add mb_skip_index 1) (ld is_first_render 0) - (mod mb_col_skip COL_SKIP) - - ; if mb_col_skip wrapped back to zero increase mb_row_skip - (cmp mb_col_skip 0) - (j.ne :not_col) - (add mb_row_skip 1) - (mod mb_row_skip ROW_SKIP) - (:not_col) + + (cmp mb_skip_index MB_SKIP_TABLE_SIZE) + ; if skip index is out of bounds, go back to repeating area + (j.lt :not_end) + (ld mb_skip_index MB_SKIP_REPEAT_INDEX) + (:not_end) (:render_not_done) (j :slp)