primitives for double-buffering

I thought I needed these for this bouncing-ball demo:

  def (bounce screen)
    with (w (width screen)
          h (height screen)
          cx 16
          cy 16
          dx 12
          dy 19)
      while 1
        clear screen
        ring screen cx cy 16 3 5
        cx += dx
        cy += dy
        when (or (cx > w) (cx < 0))
          set dx 0-dx
        when (or (cy > h) (cy < 0))
          set dy 0-dy
        for _ 0 (< _ 100) ++_         # delay

No matter how I adjusted the delay I couldn't get rid of the jitter. So
I built a double-buffered version:

    (bounce2 . [def (bounce2 screen)
  with (w (width screen)
        h (height screen)
        cx 16
        cy 16
        dx 12
        dy 19
        screen2 (new_screen (columns screen)
                            (lines screen)))
      while 1
        clear screen2
        ring screen2 cx cy 16 3 5
        cx += dx
        cy += dy
        when (or (cx > w) (cx < 0))
          set dx 0-dx
        when (or (cy > h) (cy < 0))
          set dy 0-dy
        blit screen2 screen
        for _ 0 (< _ 100) ++_])       # delay

But it didn't make a difference! Turns out nothing will help you when
successive frames are too far apart. This is the correct tweak to
`bounce`:

  -       dx 12
  -       dy 19)
  +       dx 1
  +       dy (/ 19 12))

Still, we'll keep double-buffering around for the future.
This commit is contained in:
Kartik K. Agaram 2021-07-05 23:18:30 -07:00
parent 468b0d979f
commit cbf22e7ab2
1 changed files with 152 additions and 4 deletions

View File

@ -45,6 +45,8 @@ fn initialize-primitives _self: (addr global-table) {
append-primitive self, "bezier"
append-primitive self, "width"
append-primitive self, "height"
append-primitive self, "new_screen"
append-primitive self, "blit"
# for keyboards
append-primitive self, "key"
# for streams
@ -61,7 +63,7 @@ fn initialize-primitives _self: (addr global-table) {
# evaluate all their arguments.
fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
var y/ecx: int <- copy ymax
y <- subtract 0x10/primitives-border
y <- subtract 0x11/primitives-border
clear-rect screen, xmin, y, xmax, ymax, 0xdc/bg=green-bg
y <- increment
var right-min/edx: int <- copy xmax
@ -103,7 +105,7 @@ fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
#? loop-if-=
#? }
y <- copy ymax
y <- subtract 0xf/primitives-border
y <- subtract 0x10/primitives-border
var left-max/edx: int <- copy xmax
left-max <- subtract 0x20/primitives-divider
var tmpx/eax: int <- copy xmin
@ -137,7 +139,11 @@ fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
tmpx <- draw-text-rightward screen, ": screen -> number", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
y <- increment
var tmpx/eax: int <- copy xmin
tmpx <- draw-text-rightward screen, " clear", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
tmpx <- draw-text-rightward screen, " new_screen", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
tmpx <- draw-text-rightward screen, ": number number -> screen ", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
y <- increment
var tmpx/eax: int <- copy xmin
tmpx <- draw-text-rightward screen, " clear blit", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
tmpx <- draw-text-rightward screen, ": screen", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
y <- increment
var tmpx/eax: int <- copy xmin
@ -149,7 +155,7 @@ fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
y <- increment
var tmpx/eax: int <- copy xmin
tmpx <- draw-text-rightward screen, " stream", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
tmpx <- draw-text-rightward screen, ": () -> stream ", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
tmpx <- draw-text-rightward screen, ": -> stream ", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
y <- increment
var tmpx/eax: int <- copy xmin
tmpx <- draw-text-rightward screen, " write", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
@ -486,6 +492,20 @@ fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr hand
apply-height args-ah, out, trace
return
}
{
var screen?/eax: boolean <- string-equal? f-name, "new_screen"
compare screen?, 0/false
break-if-=
apply-new-screen args-ah, out, trace
return
}
{
var blit?/eax: boolean <- string-equal? f-name, "blit"
compare blit?, 0/false
break-if-=
apply-blit args-ah, out, trace
return
}
{
var wait-for-key?/eax: boolean <- string-equal? f-name, "key"
compare wait-for-key?, 0/false
@ -3217,3 +3237,131 @@ fn apply-height _args-ah: (addr handle cell), out: (addr handle cell), trace: (a
var result/xmm0: float <- convert height
new-float out, result
}
fn apply-new-screen _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply 'screen'"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
{
var args-type/eax: (addr int) <- get args, type
compare *args-type, 0/pair
break-if-=
error trace, "args to 'screen' are not a list"
return
}
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "'screen' needs 2 args but got 0"
return
}
# args->left->value
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
{
var first-type/eax: (addr int) <- get first, type
compare *first-type, 1/number
break-if-=
error trace, "first arg for 'screen' is not a number (screen width in pixels)"
return
}
var first-value-a/ecx: (addr float) <- get first, number-data
var first-value/ecx: int <- convert *first-value-a
# args->right->left->value
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
{
var right-type/eax: (addr int) <- get right, type
compare *right-type, 0/pair
break-if-=
error trace, "'screen' encountered non-pair"
return
}
{
var nil?/eax: boolean <- nil? right
compare nil?, 0/false
break-if-=
error trace, "'screen' needs 2 args but got 1"
return
}
var second-ah/eax: (addr handle cell) <- get right, left
var second/eax: (addr cell) <- lookup *second-ah
{
var second-type/eax: (addr int) <- get second, type
compare *second-type, 1/number
break-if-=
error trace, "second arg for 'screen' is not a number (screen height in pixels)"
return
}
var second-value-a/edx: (addr float) <- get second, number-data
var second-value/edx: int <- convert *second-value-a
# create fake screen
new-fake-screen out, first-value, second-value, 1/pixel-graphics
}
fn apply-blit _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
trace-text trace, "eval", "apply 'blit'"
var args-ah/eax: (addr handle cell) <- copy _args-ah
var _args/eax: (addr cell) <- lookup *args-ah
var args/esi: (addr cell) <- copy _args
{
var args-type/eax: (addr int) <- get args, type
compare *args-type, 0/pair
break-if-=
error trace, "args to 'blit' are not a list"
return
}
var empty-args?/eax: boolean <- nil? args
compare empty-args?, 0/false
{
break-if-=
error trace, "'blit' needs 2 args but got 0"
return
}
# screen = args->left
var first-ah/eax: (addr handle cell) <- get args, left
var first/eax: (addr cell) <- lookup *first-ah
{
var first-type/eax: (addr int) <- get first, type
compare *first-type, 5/screen
break-if-=
error trace, "first arg for 'blit' is not a screen"
return
}
var src-ah/eax: (addr handle screen) <- get first, screen-data
var _src/eax: (addr screen) <- lookup *src-ah
var src/ecx: (addr screen) <- copy _src
# args->right->left
var right-ah/eax: (addr handle cell) <- get args, right
var right/eax: (addr cell) <- lookup *right-ah
{
var right-type/eax: (addr int) <- get right, type
compare *right-type, 0/pair
break-if-=
error trace, "'blit' encountered non-pair"
return
}
{
var nil?/eax: boolean <- nil? right
compare nil?, 0/false
break-if-=
error trace, "'blit' needs 2 args but got 1"
return
}
var second-ah/eax: (addr handle cell) <- get right, left
var second/eax: (addr cell) <- lookup *second-ah
{
var second-type/eax: (addr int) <- get second, type
compare *second-type, 5/screen
break-if-=
error trace, "second arg for 'blit' is not a screen"
return
}
var dest-ah/eax: (addr handle screen) <- get second, screen-data
var dest/eax: (addr screen) <- lookup *dest-ah
#
convert-graphemes-to-pixels src
copy-pixels src, dest
}