From 506a4e42a2fbbd17db5c11f8289baed2c5680ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 25 Oct 2020 11:09:23 +0100 Subject: [PATCH] Mandelbrot interactive fixes + improvements - fix memory leak caused by gradient table - refactor to conditional branches - reset drawing on move - add keys to change itercount and force redraw --- .../mandelbrot/mandelbrot-interactive.csn | 277 +++++++++++------- 1 file changed, 167 insertions(+), 110 deletions(-) diff --git a/examples/mandelbrot/mandelbrot-interactive.csn b/examples/mandelbrot/mandelbrot-interactive.csn index cc53e42..0cd5e90 100644 --- a/examples/mandelbrot/mandelbrot-interactive.csn +++ b/examples/mandelbrot/mandelbrot-interactive.csn @@ -3,22 +3,25 @@ (sc-opt SCREEN_AUTOBLIT 0) (def W 1024) (def H 768) - (def MAXITER 50) + (sym MAXITER g0) + (ld MAXITER 50) (lds @cout "Interactive Mandelbrot\n") (lds @cout "----------------------\n") - (lds @cout "Navigate using WASD, zoom using Q/E\n") + (lds @cout "Navigate using WASD, zoom: Q+/E-, detail: R+/F-; fast move/zoom: LShift, force redraw: G\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_x r7) + (sym mb_y r8) + (sym mb_s r9) + (sym mb_row r10) ; index into the skip/size table - (sym mb_skip_index r6) + (sym mb_skip_index r11) + + ; Interactive movement speed + (def ZOOM_STEP 0.1) + (def PAN_STEP 0.3) ; size of big pixels (def COL_SKIP 8) @@ -26,9 +29,9 @@ ; 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) + (sym mb_skip_table_x r12) + (sym mb_skip_table_y r13) + (sym mb_size_table r14) (mkbf mb_skip_table_x ( 0 4 0 4 2 6 0 2 4 6 2 6 0 2 4 6 ; 8x8 grid @@ -60,9 +63,14 @@ (ld mb_x 0.0) (ld mb_y 0.0) (ld mb_s 1.0) - (sym did_change r14) - (sym is_first_render r15) + (sym did_change r15) + (sym is_first_render r6) (ld is_first_render 1) + + (sym GRADIENT g1) + (mkbf GRADIENT ( + 0x421e0f 0x19071a 0x09012f 0x040449 0x000764 0x0c2c8a 0x1852b1 0x397dd1 + 0x86b5e5 0xd3ecf8 0xf1e9bf 0xf8c95f 0xffaa00 0xcc8000 0x995700 0x6a3403)) ; render row ; size - pixel size @@ -72,11 +80,6 @@ ; scale - scaling ; row - row position (proc render_row size 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) @@ -87,7 +90,7 @@ (rcmp res0 1 r0 (eq? (mod r0 res0 16) - (bfrd r0 @gradient r0) + (bfrd r0 @GRADIENT r0) ) (else? (ld r0 0)) ) @@ -96,96 +99,134 @@ (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_skip_index 0) - (:did_not_move) - - (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 r1 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_skip_index 1) - (ld is_first_render 0) - - (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) + (ret) + ) + + (:loop) + (sc-poll) + ; did_change -- did the user interact during this frame? + (ld did_change 0) + + (sym pstep r2) + (sym zstep r3) + (ld pstep PAN_STEP) + (ld zstep ZOOM_STEP) + (sc-key _ KEY_ShiftL (nz? + ; turbo mode + (fmul pstep 5.0) + (fmul zstep 5.0) + )) + (fadd zstep 1.0) + + ; scaled movement speed + (fdiv pstep mb_s) + + (tst is_first_render (z? + ; A < + (sc-key _ KEY_A (nz? + (fsub mb_x pstep) + (ld did_change 1) + (lds @cout "Pan left\n") + )) + + ; W ^ + (sc-key _ KEY_W (nz? + (fsub mb_y pstep) + (ld did_change 1) + (lds @cout "Pan up\n") + )) + + ; S v + (sc-key _ KEY_S (nz? + (fadd mb_y pstep) + (ld did_change 1) + (lds @cout "Pan down\n") + )) + + ; D > + (sc-key _ KEY_D (nz? + (fadd mb_x pstep) + (ld did_change 1) + (lds @cout "Pan right\n") + )) + + ; Q + + (sc-key r0 KEY_Q (nz? + (fmul mb_s zstep) + (ld did_change 1) + (lds @cout "Zoom in\n") + )) + + ; E - + (sc-key r0 KEY_E (nz? + (fdiv mb_s zstep) + (ld did_change 1) + (lds @cout "Zoom out\n") + )) + + ; R iter+ + (sc-key r0 KEY_R (nz? + (add MAXITER 50) + (lds @cout "ITER=") (call printnum MAXITER) (ld @cout '\n') + (mslp 200) ; Avoid unexpected rapid change + )) + + ; F iter- + (sc-key r0 KEY_F (nz? + (cmp MAXITER 50) + (sub.gt MAXITER 50) + (lds @cout "ITER=") (call printnum MAXITER) (ld @cout '\n') + (mslp 200) ; Avoid unexpected rapid change + )) + + ; G force redraw + (sc-key r0 KEY_G (nz? + (ld did_change 1) + )) + + (tst did_change (nz? + ; something changed... + ; mark this as a first render and reset col_skip and row_skip + (ld is_first_render 1) + (ld mb_skip_index 0) + ; Start from top + (ld mb_row 0) + )) + )) + (unsym pstep) + (unsym zstep) + + (sym mb_col_skip r2) + (sym mb_row_skip r3) + (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 r1 mb_col_skip mb_x mb_y mb_s r0) + (unsym mb_col_skip) + (unsym mb_row_skip) + + (cmp mb_row H + (lt? + ; if mb_row < H + (add mb_row ROW_SKIP) + ) + (else? + ; otherwise, this frame is done + (ld mb_row 0) + (add mb_skip_index 1) + (ld is_first_render 0) + + (cmp mb_skip_index MB_SKIP_TABLE_SIZE (ge? + ; if skip index is out of bounds, go back to repeating area + (ld mb_skip_index MB_SKIP_REPEAT_INDEX) + )) + ) + ) + (j :loop) (proc pixel xi yi off_x off_y scale (sym x0 r7) @@ -239,5 +280,21 @@ (:end) (ret iter) ) + + (proc printnum num + (mkbf r15) + (ld r1 num) + (tst r1 (<0? (mul r1 -1))) + (:next) + (mod r0 r1 10) + (add r0 '0') + (bfrpush @r15 r0) + (div r1 10 (z? + (tst num (<0? (bfrpush @r15 '-'))) + (lds @cout @r15) + (del @r15) + (ret))) + (j :next) + ) )