1b09418c60
So far we've drawn a space implicitly at the cursor. Now I allow drawing an arbitrary grapheme when drawing the cursor. But the caller has to specify what to draw. (The alternative would be for layer 103 to track every single grapheme on screen along with its color and any other future attributes, just to be able to paint and unpaint the background for a single character.) I've modified existing helpers for drawing multiple graphemes to always clear the final cursor position after they finish drawing. That seems reasonable for terminal-like applications. Applications that need to control the screen in a more random-access manner will need to track the grapheme at the cursor for themselves.
254 lines
7.2 KiB
Forth
254 lines
7.2 KiB
Forth
# Testable primitives for writing text to screen.
|
|
# (Mu doesn't yet have testable primitives for graphics.)
|
|
#
|
|
# Unlike the top-level, this text mode has no scrolling.
|
|
|
|
# coordinates here don't match top-level
|
|
# Here we're consistent with graphics mode. Top-level is consistent with
|
|
# terminal emulators.
|
|
type screen {
|
|
width: int
|
|
height: int
|
|
data: (handle array screen-cell)
|
|
cursor-x: int
|
|
cursor-y: int
|
|
}
|
|
|
|
type screen-cell {
|
|
data: grapheme
|
|
color: int
|
|
}
|
|
|
|
fn initialize-screen screen: (addr screen), width: int, height: int {
|
|
var screen-addr/esi: (addr screen) <- copy screen
|
|
var tmp/eax: int <- copy 0
|
|
var dest/edi: (addr int) <- copy 0
|
|
# screen->width = width
|
|
dest <- get screen-addr, width
|
|
tmp <- copy width
|
|
copy-to *dest, tmp
|
|
# screen->height = height
|
|
dest <- get screen-addr, height
|
|
tmp <- copy height
|
|
copy-to *dest, tmp
|
|
# screen->data = new screen-cell[width*height]
|
|
{
|
|
var data-addr/edi: (addr handle array screen-cell) <- get screen-addr, data
|
|
tmp <- multiply width
|
|
populate data-addr, tmp
|
|
}
|
|
# screen->cursor-x = 0
|
|
dest <- get screen-addr, cursor-x
|
|
copy-to *dest, 0
|
|
# screen->cursor-y = 0
|
|
dest <- get screen-addr, cursor-y
|
|
copy-to *dest, 0
|
|
}
|
|
|
|
# in graphemes
|
|
fn screen-size screen: (addr screen) -> _/eax: int, _/ecx: int {
|
|
var width/eax: int <- copy 0
|
|
var height/ecx: int <- copy 0
|
|
compare screen, 0
|
|
{
|
|
break-if-!=
|
|
return 0x80, 0x30 # 128x48
|
|
}
|
|
# fake screen
|
|
var screen-addr/esi: (addr screen) <- copy screen
|
|
var tmp/edx: (addr int) <- get screen-addr, width
|
|
width <- copy *tmp
|
|
tmp <- get screen-addr, height
|
|
height <- copy *tmp
|
|
return width, height
|
|
}
|
|
|
|
# testable screen primitive
|
|
# background color isn't configurable yet
|
|
fn draw-grapheme screen: (addr screen), g: grapheme, x: int, y: int, color: int {
|
|
{
|
|
compare screen, 0
|
|
break-if-!=
|
|
draw-grapheme-on-real-screen g, x, y, color, 0
|
|
return
|
|
}
|
|
# fake screen
|
|
var screen-addr/esi: (addr screen) <- copy screen
|
|
var idx/ecx: int <- screen-cell-index screen-addr, x, y
|
|
var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
|
|
var data/eax: (addr array screen-cell) <- lookup *data-ah
|
|
var offset/ecx: (offset screen-cell) <- compute-offset data, idx
|
|
var dest-cell/ecx: (addr screen-cell) <- index data, offset
|
|
var dest-grapheme/eax: (addr grapheme) <- get dest-cell, data
|
|
var g2/edx: grapheme <- copy g
|
|
copy-to *dest-grapheme, g2
|
|
var dest-color/eax: (addr int) <- get dest-cell, color
|
|
var color2/edx: grapheme <- copy color
|
|
copy-to *dest-color, color2
|
|
}
|
|
|
|
fn screen-cell-index screen-on-stack: (addr screen), x: int, y: int -> _/ecx: int {
|
|
var screen/esi: (addr screen) <- copy screen-on-stack
|
|
var height-addr/eax: (addr int) <- get screen, height
|
|
var result/ecx: int <- copy y
|
|
result <- multiply *height-addr
|
|
result <- add x
|
|
return result
|
|
}
|
|
|
|
fn cursor-position screen: (addr screen) -> _/eax: int, _/ecx: int {
|
|
{
|
|
compare screen, 0
|
|
break-if-!=
|
|
var x/eax: int <- copy 0
|
|
var y/ecx: int <- copy 0
|
|
x, y <- cursor-position-on-real-screen
|
|
return x, y
|
|
}
|
|
# fake screen
|
|
var screen-addr/esi: (addr screen) <- copy screen
|
|
var cursor-x-addr/eax: (addr int) <- get screen-addr, cursor-x
|
|
var cursor-y-addr/ecx: (addr int) <- get screen-addr, cursor-y
|
|
return *cursor-x-addr, *cursor-y-addr
|
|
}
|
|
|
|
fn set-cursor-position screen: (addr screen), x: int, y: int, g: grapheme {
|
|
{
|
|
compare screen, 0
|
|
break-if-!=
|
|
set-cursor-position-on-real-screen x, y, g
|
|
return
|
|
}
|
|
# fake screen
|
|
var screen-addr/esi: (addr screen) <- copy screen
|
|
# ignore x < 0
|
|
{
|
|
compare x, 0
|
|
break-if->=
|
|
return
|
|
}
|
|
# ignore x >= width
|
|
{
|
|
var width-addr/eax: (addr int) <- get screen-addr, width
|
|
var width/eax: int <- copy *width-addr
|
|
compare x, width
|
|
break-if-<=
|
|
return
|
|
}
|
|
# ignore y < 0
|
|
{
|
|
compare y, 0
|
|
break-if->=
|
|
return
|
|
}
|
|
# ignore y >= height
|
|
{
|
|
var height-addr/eax: (addr int) <- get screen-addr, height
|
|
var height/eax: int <- copy *height-addr
|
|
compare y, height
|
|
break-if-<
|
|
return
|
|
}
|
|
# screen->cursor-x = x
|
|
var dest/edi: (addr int) <- get screen-addr, cursor-x
|
|
var src/eax: int <- copy x
|
|
copy-to *dest, src
|
|
# screen->cursor-y = y
|
|
dest <- get screen-addr, cursor-y
|
|
src <- copy y
|
|
copy-to *dest, src
|
|
#
|
|
var cursor-x/eax: int <- copy 0
|
|
var cursor-y/ecx: int <- copy 0
|
|
cursor-x, cursor-y <- cursor-position screen-addr
|
|
draw-grapheme screen-addr, g, cursor-x, cursor-y, 0 # cursor color not tracked for fake screen
|
|
}
|
|
|
|
fn clear-screen screen: (addr screen) {
|
|
{
|
|
compare screen, 0
|
|
break-if-!=
|
|
clear-real-screen
|
|
return
|
|
}
|
|
# fake screen
|
|
var space/edi: grapheme <- copy 0x20
|
|
set-cursor-position screen, 0, 0, space
|
|
var screen-addr/esi: (addr screen) <- copy screen
|
|
var y/eax: int <- copy 1
|
|
var height/ecx: (addr int) <- get screen-addr, height
|
|
{
|
|
compare y, *height
|
|
break-if->
|
|
var x/edx: int <- copy 1
|
|
var width/ebx: (addr int) <- get screen-addr, width
|
|
{
|
|
compare x, *width
|
|
break-if->
|
|
draw-grapheme screen, space, x, y, 0 # color=black
|
|
x <- increment
|
|
loop
|
|
}
|
|
y <- increment
|
|
loop
|
|
}
|
|
set-cursor-position screen, 0, 0, space
|
|
}
|
|
|
|
# there's no grapheme that guarantees to cover every pixel, so we'll bump down
|
|
# to pixels for a real screen
|
|
fn clear-real-screen {
|
|
var y/eax: int <- copy 0
|
|
{
|
|
compare y, 0x300 # screen-height = 768
|
|
break-if->=
|
|
var x/edx: int <- copy 0
|
|
{
|
|
compare x, 0x400 # screen-width = 1024
|
|
break-if->=
|
|
pixel-on-real-screen x, y, 0 # black
|
|
x <- increment
|
|
loop
|
|
}
|
|
y <- increment
|
|
loop
|
|
}
|
|
}
|
|
|
|
fn screen-grapheme-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: grapheme {
|
|
var screen-addr/esi: (addr screen) <- copy screen-on-stack
|
|
var idx/ecx: int <- screen-cell-index screen-addr, x, y
|
|
var result/eax: grapheme <- screen-grapheme-at-idx screen-addr, idx
|
|
return result
|
|
}
|
|
|
|
fn screen-grapheme-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: grapheme {
|
|
var screen-addr/esi: (addr screen) <- copy screen-on-stack
|
|
var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
|
|
var data/eax: (addr array screen-cell) <- lookup *data-ah
|
|
var idx/ecx: int <- copy idx-on-stack
|
|
var offset/ecx: (offset screen-cell) <- compute-offset data, idx
|
|
var cell/eax: (addr screen-cell) <- index data, offset
|
|
var src/eax: (addr grapheme) <- get cell, data
|
|
return *src
|
|
}
|
|
|
|
fn screen-color-at screen-on-stack: (addr screen), x: int, y: int -> _/eax: int {
|
|
var screen-addr/esi: (addr screen) <- copy screen-on-stack
|
|
var idx/ecx: int <- screen-cell-index screen-addr, x, y
|
|
var result/eax: int <- screen-color-at-idx screen-addr, idx
|
|
return result
|
|
}
|
|
|
|
fn screen-color-at-idx screen-on-stack: (addr screen), idx-on-stack: int -> _/eax: int {
|
|
var screen-addr/esi: (addr screen) <- copy screen-on-stack
|
|
var data-ah/eax: (addr handle array screen-cell) <- get screen-addr, data
|
|
var data/eax: (addr array screen-cell) <- lookup *data-ah
|
|
var idx/ecx: int <- copy idx-on-stack
|
|
var offset/ecx: (offset screen-cell) <- compute-offset data, idx
|
|
var cell/eax: (addr screen-cell) <- index data, offset
|
|
var src/eax: (addr int) <- get cell, color
|
|
var result/eax: int <- copy *src
|
|
return result
|
|
}
|