flickerlessly render fake screens in environment
Font rendering now happens off the real screen, which provides the effect of double-buffering. Apps can now also use convert-graphemes-to-pixels for more traditional double-buffering.
This commit is contained in:
parent
b9fea69687
commit
c2c6f4c7ab
|
@ -26,6 +26,50 @@ $draw-grapheme-on-real-screen:end:
|
|||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
draw-grapheme-on-screen-array: # screen-data: (addr array byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
|
||||
# . prologue
|
||||
55/push-ebp
|
||||
89/<- %ebp 4/r32/esp
|
||||
# . save registers
|
||||
50/push-eax
|
||||
51/push-ecx
|
||||
52/push-edx
|
||||
# if screen-width*screen-height > len(screen-data) abort
|
||||
{
|
||||
# ecx = len(screen-data)
|
||||
8b/-> *(ebp+8) 1/r32/ecx
|
||||
8b/-> *ecx 1/r32/ecx
|
||||
# eax = screen-width*screen-height
|
||||
ba/copy-to-edx 0/imm32
|
||||
8b/-> *(ebp+0x20) 0/r32/eax
|
||||
f7 4/subop/multiply-into-eax *(ebp+0x24)
|
||||
81 7/subop/compare %edx 0/imm32
|
||||
0f 85/jump-if-!= $draw-grapheme-on-screen-array:overflow/disp32
|
||||
# if (eax > ecx) abort
|
||||
39/compare %eax 1/r32/ecx
|
||||
0f 8f/jump-if-> $draw-grapheme-on-screen-array:abort/disp32
|
||||
}
|
||||
# eax = screen-data+4 (skip length)
|
||||
8b/-> *(ebp+8) 0/r32/eax
|
||||
05/add-to-eax 4/imm32
|
||||
#
|
||||
(draw-grapheme-on-screen-buffer %eax *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18) *(ebp+0x1c) *(ebp+0x20) *(ebp+0x24))
|
||||
$draw-grapheme-on-screen-array:end:
|
||||
# . restore registers
|
||||
5a/pop-to-edx
|
||||
59/pop-to-ecx
|
||||
58/pop-to-eax
|
||||
# . epilogue
|
||||
89/<- %esp 5/r32/ebp
|
||||
5d/pop-to-ebp
|
||||
c3/return
|
||||
|
||||
$draw-grapheme-on-screen-array:overflow:
|
||||
(abort "draw-grapheme-on-screen-array: screen dimensions too large")
|
||||
|
||||
$draw-grapheme-on-screen-array:abort:
|
||||
(abort "draw-grapheme-on-screen-array: coordinates are off the screen. Are the screen dimensions correct?")
|
||||
|
||||
# 'buffer' here is not a valid Mu type: a naked address without a length.
|
||||
draw-grapheme-on-screen-buffer: # buffer: (addr byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
|
||||
# . prologue
|
||||
|
|
1
400.mu
1
400.mu
|
@ -1,6 +1,7 @@
|
|||
# screen
|
||||
sig pixel-on-real-screen x: int, y: int, color: int
|
||||
sig draw-grapheme-on-real-screen g: grapheme, x: int, y: int, color: int, background-color: int
|
||||
sig draw-grapheme-on-screen-array screen-data: (addr array byte), g: grapheme, x: int, y: int, color: int, background-color: int, screen-width: int, screen-height: int
|
||||
sig cursor-position-on-real-screen -> _/eax: int, _/ecx: int
|
||||
sig set-cursor-position-on-real-screen x: int, y: int
|
||||
sig draw-cursor-on-real-screen g: grapheme
|
||||
|
|
|
@ -268,7 +268,7 @@ fn clear-screen _screen: (addr screen) {
|
|||
{
|
||||
compare x, *width
|
||||
break-if->=
|
||||
draw-code-point screen, 0x20/space, x, y, 0/fg=black, 0/bg=black
|
||||
draw-code-point screen, 0/nul, x, y, 0/fg=black, 0/bg=black
|
||||
x <- increment
|
||||
loop
|
||||
}
|
||||
|
@ -580,3 +580,47 @@ fn copy-pixels _screen: (addr screen), target-screen: (addr screen) {
|
|||
loop
|
||||
}
|
||||
}
|
||||
|
||||
# It turns out double-buffering graphemes is useless because rendering fonts
|
||||
# takes too long. (At least under Qemu.)
|
||||
# So we'll instead convert graphemes to pixels when double-buffering.
|
||||
# 'screen' must be a fake screen.
|
||||
fn convert-graphemes-to-pixels _screen: (addr screen) {
|
||||
var screen/esi: (addr screen) <- copy _screen
|
||||
var width-a/ebx: (addr int) <- get screen, width
|
||||
var height-a/edx: (addr int) <- get screen, height
|
||||
var data-ah/eax: (addr handle array byte) <- get screen, pixels
|
||||
var _data/eax: (addr array byte) <- lookup *data-ah
|
||||
var data: (addr array byte)
|
||||
copy-to data, _data
|
||||
var y/ecx: int <- copy 0
|
||||
{
|
||||
compare y, *height-a
|
||||
break-if->=
|
||||
var x/edi: int <- copy 0
|
||||
{
|
||||
compare x, *width-a
|
||||
break-if->=
|
||||
{
|
||||
var tmp/eax: grapheme <- screen-grapheme-at screen, x, y
|
||||
# skip null graphemes that only get created when clearing screen
|
||||
# there may be other pixels drawn there, and we don't want to clobber them
|
||||
# this is a situation where fake screens aren't faithful to real screens; we don't support overlap between graphemes and raw pixels
|
||||
compare tmp, 0
|
||||
break-if-=
|
||||
abort "bb"
|
||||
var g: grapheme
|
||||
copy-to g, tmp
|
||||
var tmp/eax: int <- screen-color-at screen, x, y
|
||||
var fg: int
|
||||
copy-to fg, tmp
|
||||
var bg/eax: int <- screen-background-color-at screen, x, y
|
||||
draw-grapheme-on-screen-array data, g, x, y, fg, bg, *width-a, *height-a
|
||||
}
|
||||
x <- increment
|
||||
loop
|
||||
}
|
||||
y <- increment
|
||||
loop
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ fn evaluate _in-ah: (addr handle cell), _out-ah: (addr handle cell), env-h: (han
|
|||
var screen-obj/eax: (addr screen) <- lookup *screen-obj-ah
|
||||
compare screen-obj, 0
|
||||
break-if-=
|
||||
var y/ecx: int <- render-screen 0/screen, screen-obj, 0x58/xmin, 2/ymin
|
||||
render-screen 0/screen, screen-obj, 0x58/xmin, 2/ymin
|
||||
var key/eax: byte <- read-key 0/keyboard
|
||||
compare key, 0
|
||||
break-if-=
|
||||
|
|
|
@ -124,7 +124,7 @@ fn render-sandbox screen: (addr screen), _self: (addr sandbox), xmin: int, ymin:
|
|||
var dummy/eax: int <- draw-stream-rightward screen, value, x2, xmax, y, 7/fg=grey, 0xc5/bg=blue-bg
|
||||
}
|
||||
y <- add 2 # padding
|
||||
y <- maybe-render-screen screen, self, xmin, y
|
||||
maybe-render-screen screen, self, xmin, y
|
||||
}
|
||||
|
||||
fn render-sandbox-menu screen: (addr screen), _self: (addr sandbox) {
|
||||
|
@ -195,20 +195,20 @@ fn maybe-render-empty-screen screen: (addr screen), _self: (addr sandbox), xmin:
|
|||
return y
|
||||
}
|
||||
|
||||
fn maybe-render-screen screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int -> _/ecx: int {
|
||||
fn maybe-render-screen screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int {
|
||||
var self/esi: (addr sandbox) <- copy _self
|
||||
var screen-obj-cell-ah/eax: (addr handle cell) <- get self, screen-var
|
||||
var screen-obj-cell/eax: (addr cell) <- lookup *screen-obj-cell-ah
|
||||
compare screen-obj-cell, 0
|
||||
{
|
||||
break-if-!=
|
||||
return ymin
|
||||
return
|
||||
}
|
||||
var screen-obj-cell-type/ecx: (addr int) <- get screen-obj-cell, type
|
||||
compare *screen-obj-cell-type, 5/screen
|
||||
{
|
||||
break-if-=
|
||||
return ymin # silently give up on rendering the screen
|
||||
return # silently give up on rendering the screen
|
||||
}
|
||||
var screen-obj-ah/eax: (addr handle screen) <- get screen-obj-cell, screen-data
|
||||
var _screen-obj/eax: (addr screen) <- lookup *screen-obj-ah
|
||||
|
@ -217,15 +217,14 @@ fn maybe-render-screen screen: (addr screen), _self: (addr sandbox), xmin: int,
|
|||
var screen-empty?/eax: boolean <- fake-screen-empty? screen-obj
|
||||
compare screen-empty?, 0/false
|
||||
break-if-=
|
||||
return ymin
|
||||
return
|
||||
}
|
||||
var x/eax: int <- draw-text-rightward screen, "screen: ", xmin, 0x99/xmax, ymin, 0x17/fg, 0xc5/bg=blue-bg
|
||||
x <- copy xmin
|
||||
x <- add 2
|
||||
var y/ecx: int <- copy ymin
|
||||
y <- increment
|
||||
y <- render-screen screen, screen-obj, x, y
|
||||
return y
|
||||
render-screen screen, screen-obj, x, y
|
||||
}
|
||||
|
||||
fn render-empty-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int -> _/ecx: int {
|
||||
|
@ -255,32 +254,10 @@ fn render-empty-screen screen: (addr screen), _target-screen: (addr screen), xmi
|
|||
return screen-y
|
||||
}
|
||||
|
||||
fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int -> _/ecx: int {
|
||||
fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int {
|
||||
var target-screen/esi: (addr screen) <- copy _target-screen
|
||||
var screen-y/edi: int <- copy ymin
|
||||
# text data
|
||||
{
|
||||
var height/edx: (addr int) <- get target-screen, height
|
||||
var y/ecx: int <- copy 0
|
||||
{
|
||||
compare y, *height
|
||||
break-if->=
|
||||
set-cursor-position screen, xmin, screen-y
|
||||
var width/edx: (addr int) <- get target-screen, width
|
||||
var x/ebx: int <- copy 0
|
||||
{
|
||||
compare x, *width
|
||||
break-if->=
|
||||
print-screen-cell-of-fake-screen screen, target-screen, x, y
|
||||
move-cursor-right screen
|
||||
x <- increment
|
||||
loop
|
||||
}
|
||||
y <- increment
|
||||
screen-y <- increment
|
||||
loop
|
||||
}
|
||||
}
|
||||
convert-graphemes-to-pixels target-screen # might overwrite existing pixel data with graphemes
|
||||
# overlapping the two is not supported
|
||||
# pixel data
|
||||
{
|
||||
# screen top left pixels x y width height
|
||||
|
@ -331,7 +308,6 @@ fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int
|
|||
loop
|
||||
}
|
||||
}
|
||||
return screen-y
|
||||
}
|
||||
|
||||
fn has-keyboard? _self: (addr sandbox) -> _/eax: boolean {
|
||||
|
|
Loading…
Reference in New Issue