shell: pixel graphics
This commit is contained in:
parent
5a3f9a3185
commit
bbabe8bd1a
|
@ -1,17 +1,25 @@
|
|||
# Testable primitives for writing text to screen.
|
||||
# (Mu doesn't yet have testable primitives for graphics.)
|
||||
# Testable primitives for writing to screen.
|
||||
#
|
||||
# Unlike the top-level, this text mode has no scrolling.
|
||||
# Mu mostly uses the screen for text, but it builds it out of pixel graphics
|
||||
# and a bitmap font. There is no support for a blinking cursor, scrolling and
|
||||
# so on.
|
||||
#
|
||||
# Fake screens are primarily for testing text-mode prints. However, they do
|
||||
# support some rudimentary pixel operations as well. Caveats:
|
||||
#
|
||||
# - Drawing pixels atop text or vice versa is not supported. Results in a fake
|
||||
# screen will not mimic real screens in these situations.
|
||||
# - Fake screens currently also assume a fixed-width 8x16 font.
|
||||
|
||||
# coordinates here don't match top-level
|
||||
# Here we're consistent with graphics mode. Top-level is consistent with
|
||||
# terminal emulators.
|
||||
type screen {
|
||||
# text mode
|
||||
width: int
|
||||
height: int
|
||||
data: (handle array screen-cell)
|
||||
cursor-x: int
|
||||
cursor-y: int
|
||||
cursor-x: int # [0..width)
|
||||
cursor-y: int # [0..height)
|
||||
# pixel graphics
|
||||
pixels: (handle stream pixel) # sparse representation
|
||||
}
|
||||
|
||||
type screen-cell {
|
||||
|
@ -20,6 +28,12 @@ type screen-cell {
|
|||
background-color: int
|
||||
}
|
||||
|
||||
type pixel {
|
||||
x: int # [0..width*font-width)
|
||||
y: int # [0..height*font-height)
|
||||
color: int # [0..256)
|
||||
}
|
||||
|
||||
fn initialize-screen _screen: (addr screen), width: int, height: int {
|
||||
var screen/esi: (addr screen) <- copy _screen
|
||||
var tmp/eax: int <- copy 0
|
||||
|
@ -38,6 +52,9 @@ fn initialize-screen _screen: (addr screen), width: int, height: int {
|
|||
tmp <- multiply width
|
||||
populate data-addr, tmp
|
||||
}
|
||||
# pixels
|
||||
var pixels-ah/ecx: (addr handle stream pixel) <- get screen, pixels
|
||||
populate-stream pixels-ah, tmp
|
||||
# screen->cursor-x = 0
|
||||
dest <- get screen, cursor-x
|
||||
copy-to *dest, 0
|
||||
|
@ -64,6 +81,33 @@ fn screen-size _screen: (addr screen) -> _/eax: int, _/ecx: int {
|
|||
return width, height
|
||||
}
|
||||
|
||||
fn pixel screen: (addr screen), x: int, y: int, color: int {
|
||||
{
|
||||
compare screen, 0
|
||||
break-if-!=
|
||||
pixel-on-real-screen x, y, color
|
||||
return
|
||||
}
|
||||
# fake screen
|
||||
# prepare a pixel
|
||||
var pixel-storage: pixel
|
||||
var src/ecx: int <- copy x
|
||||
var dest/edx: (addr int) <- get pixel-storage, x
|
||||
copy-to *dest, src
|
||||
src <- copy y
|
||||
dest <- get pixel-storage, y
|
||||
copy-to *dest, src
|
||||
src <- copy color
|
||||
dest <- get pixel-storage, color
|
||||
copy-to *dest, src
|
||||
# save it
|
||||
var src/ecx: (addr pixel) <- address pixel-storage
|
||||
var screen/eax: (addr screen) <- copy screen
|
||||
var dest-stream-ah/eax: (addr handle stream pixel) <- get screen, pixels
|
||||
var dest-stream/eax: (addr stream pixel) <- lookup *dest-stream-ah
|
||||
write-to-stream dest-stream, src
|
||||
}
|
||||
|
||||
# testable screen primitive
|
||||
fn draw-grapheme _screen: (addr screen), g: grapheme, x: int, y: int, color: int, background-color: int {
|
||||
var screen/esi: (addr screen) <- copy _screen
|
||||
|
@ -219,6 +263,9 @@ fn clear-screen _screen: (addr screen) {
|
|||
loop
|
||||
}
|
||||
set-cursor-position screen, 0, 0
|
||||
var dest-stream-ah/eax: (addr handle stream pixel) <- get screen, pixels
|
||||
var dest-stream/eax: (addr stream pixel) <- lookup *dest-stream-ah
|
||||
clear-stream dest-stream
|
||||
}
|
||||
|
||||
fn fake-screen-empty? _screen: (addr screen) -> _/eax: boolean {
|
||||
|
@ -247,7 +294,10 @@ fn fake-screen-empty? _screen: (addr screen) -> _/eax: boolean {
|
|||
y <- increment
|
||||
loop
|
||||
}
|
||||
return 1/true
|
||||
var pixels-ah/eax: (addr handle stream pixel) <- get screen, pixels
|
||||
var pixels/eax: (addr stream pixel) <- lookup *pixels-ah
|
||||
var result/eax: boolean <- stream-empty? pixels
|
||||
return result
|
||||
}
|
||||
|
||||
fn clear-rect _screen: (addr screen), xmin: int, ymin: int, xmax: int, ymax: int, background-color: int {
|
|
@ -26,6 +26,7 @@ fn initialize-globals _self: (addr global-table) {
|
|||
append-primitive self, "cons"
|
||||
# for screens
|
||||
append-primitive self, "print"
|
||||
append-primitive self, "pixel"
|
||||
# for keyboards
|
||||
append-primitive self, "key"
|
||||
# for streams
|
||||
|
@ -302,6 +303,13 @@ fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr hand
|
|||
apply-print args-ah, out, trace
|
||||
return
|
||||
}
|
||||
{
|
||||
var is-pixel?/eax: boolean <- string-equal? f-name, "pixel"
|
||||
compare is-pixel?, 0/false
|
||||
break-if-=
|
||||
apply-pixel args-ah, out, trace
|
||||
return
|
||||
}
|
||||
{
|
||||
var wait-for-key?/eax: boolean <- string-equal? f-name, "key"
|
||||
compare wait-for-key?, 0/false
|
||||
|
@ -686,6 +694,84 @@ fn apply-print _args-ah: (addr handle cell), out: (addr handle cell), trace: (ad
|
|||
copy-object second-ah, out
|
||||
}
|
||||
|
||||
fn apply-pixel _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
|
||||
trace-text trace, "eval", "apply pixel"
|
||||
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
|
||||
# TODO: check that args is a pair
|
||||
var empty-args?/eax: boolean <- nil? args
|
||||
compare empty-args?, 0/false
|
||||
{
|
||||
break-if-=
|
||||
error trace, "pixel needs 4 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/ecx: (addr int) <- get first, type
|
||||
compare *first-type, 5/screen
|
||||
{
|
||||
break-if-=
|
||||
error trace, "first arg for 'pixel' is not a screen"
|
||||
return
|
||||
}
|
||||
var screen-ah/eax: (addr handle screen) <- get first, screen-data
|
||||
var _screen/eax: (addr screen) <- lookup *screen-ah
|
||||
var screen/edi: (addr screen) <- copy _screen
|
||||
# x = args->right->left->value
|
||||
var rest-ah/eax: (addr handle cell) <- get args, right
|
||||
var _rest/eax: (addr cell) <- lookup *rest-ah
|
||||
var rest/esi: (addr cell) <- copy _rest
|
||||
# TODO: check that rest is a pair
|
||||
var second-ah/eax: (addr handle cell) <- get rest, left
|
||||
var second/eax: (addr cell) <- lookup *second-ah
|
||||
var second-type/ecx: (addr int) <- get second, type
|
||||
compare *second-type, 1/number
|
||||
{
|
||||
break-if-=
|
||||
error trace, "second arg for 'pixel' is not an int (x coordinate)"
|
||||
return
|
||||
}
|
||||
var second-value/eax: (addr float) <- get second, number-data
|
||||
var x/edx: int <- convert *second-value
|
||||
# y = rest->right->left->value
|
||||
var rest-ah/eax: (addr handle cell) <- get rest, right
|
||||
var _rest/eax: (addr cell) <- lookup *rest-ah
|
||||
rest <- copy _rest
|
||||
# TODO: check that rest is a pair
|
||||
var third-ah/eax: (addr handle cell) <- get rest, left
|
||||
var third/eax: (addr cell) <- lookup *third-ah
|
||||
var third-type/ecx: (addr int) <- get third, type
|
||||
compare *third-type, 1/number
|
||||
{
|
||||
break-if-=
|
||||
error trace, "third arg for 'pixel' is not an int (y coordinate)"
|
||||
return
|
||||
}
|
||||
var third-value/eax: (addr float) <- get third, number-data
|
||||
var y/ebx: int <- convert *third-value
|
||||
# color = rest->right->left->value
|
||||
var rest-ah/eax: (addr handle cell) <- get rest, right
|
||||
var _rest/eax: (addr cell) <- lookup *rest-ah
|
||||
rest <- copy _rest
|
||||
# TODO: check that rest is a pair
|
||||
var fourth-ah/eax: (addr handle cell) <- get rest, left
|
||||
var fourth/eax: (addr cell) <- lookup *fourth-ah
|
||||
var fourth-type/ecx: (addr int) <- get fourth, type
|
||||
compare *fourth-type, 1/number
|
||||
{
|
||||
break-if-=
|
||||
error trace, "fourth arg for 'pixel' is not an int (color; 0..0xff)"
|
||||
return
|
||||
}
|
||||
var fourth-value/eax: (addr float) <- get fourth, number-data
|
||||
var color/eax: int <- convert *fourth-value
|
||||
pixel screen, x, y, color
|
||||
# return nothing
|
||||
}
|
||||
|
||||
fn apply-wait-for-key _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
|
||||
trace-text trace, "eval", "apply key"
|
||||
var args-ah/eax: (addr handle cell) <- copy _args-ah
|
||||
|
|
|
@ -250,29 +250,61 @@ fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int
|
|||
}
|
||||
screen-y <- increment
|
||||
}
|
||||
# screen
|
||||
var height/edx: (addr int) <- get target-screen, height
|
||||
var y/ecx: int <- copy 0
|
||||
# text data
|
||||
{
|
||||
compare y, *height
|
||||
break-if->=
|
||||
set-cursor-position screen, xmin, screen-y
|
||||
draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x18/fg, 0/bg
|
||||
move-cursor-right screen
|
||||
var width/edx: (addr int) <- get target-screen, width
|
||||
var x/ebx: int <- copy 0
|
||||
var height/edx: (addr int) <- get target-screen, height
|
||||
var y/ecx: int <- copy 0
|
||||
{
|
||||
compare x, *width
|
||||
compare y, *height
|
||||
break-if->=
|
||||
print-screen-cell-of-fake-screen screen, target-screen, x, y
|
||||
set-cursor-position screen, xmin, screen-y
|
||||
draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x18/fg, 0/bg
|
||||
move-cursor-right screen
|
||||
x <- increment
|
||||
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
|
||||
}
|
||||
draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x18/fg, 0/bg
|
||||
y <- increment
|
||||
screen-y <- increment
|
||||
loop
|
||||
}
|
||||
}
|
||||
# pixel data
|
||||
{
|
||||
var left/ebx: int <- copy xmin
|
||||
left <- add 1/margin-left
|
||||
left <- shift-left 3/log-font-width
|
||||
var top/edx: int <- copy ymin
|
||||
top <- add 1/margin-top
|
||||
top <- shift-left 4/log-font-height
|
||||
var pixels-ah/esi: (addr handle stream pixel) <- get target-screen, pixels
|
||||
var _pixels/eax: (addr stream pixel) <- lookup *pixels-ah
|
||||
var pixels/esi: (addr stream pixel) <- copy _pixels
|
||||
rewind-stream pixels
|
||||
{
|
||||
var done?/eax: boolean <- stream-empty? pixels
|
||||
compare done?, 0/false
|
||||
break-if-!=
|
||||
var curr-pixel: pixel
|
||||
var curr-pixel-addr/eax: (addr pixel) <- address curr-pixel
|
||||
read-from-stream pixels, curr-pixel-addr
|
||||
var curr-x/eax: (addr int) <- get curr-pixel, x
|
||||
var x/eax: int <- copy *curr-x
|
||||
x <- add left
|
||||
var curr-y/ecx: (addr int) <- get curr-pixel, y
|
||||
var y/ecx: int <- copy *curr-y
|
||||
y <- add top
|
||||
var curr-color/edx: (addr int) <- get curr-pixel, color
|
||||
pixel screen, x, y, *curr-color
|
||||
loop
|
||||
}
|
||||
draw-code-point-at-cursor screen, 0x7c/vertical-bar, 0x18/fg, 0/bg
|
||||
y <- increment
|
||||
screen-y <- increment
|
||||
loop
|
||||
}
|
||||
# bottom border
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue