Turn the display portrait and split it into live and since-reset panels
This commit is contained in:
@@ -31,6 +31,9 @@ const (
|
||||
viScreenInfoLen = 40
|
||||
)
|
||||
|
||||
// w and h are the logical canvas, which is portrait; pw and ph are the panel,
|
||||
// which is landscape. Every draw is turned a quarter turn on its way to memory,
|
||||
// so logical top lands on the panel's right edge.
|
||||
type framebuffer struct {
|
||||
file *os.File
|
||||
tty *os.File
|
||||
@@ -38,12 +41,22 @@ type framebuffer struct {
|
||||
back []byte
|
||||
w int
|
||||
h int
|
||||
pw int
|
||||
ph int
|
||||
stride int
|
||||
rShift uint
|
||||
gShift uint
|
||||
bShift uint
|
||||
}
|
||||
|
||||
func (fb *framebuffer) offset(x, y int) int {
|
||||
return x*fb.stride + (fb.pw-1-y)*4
|
||||
}
|
||||
|
||||
func (fb *framebuffer) fromPanel(x, y int) (int, int) {
|
||||
return y, fb.pw - 1 - x
|
||||
}
|
||||
|
||||
// The kernel console draws into the same framebuffer, including a blinking
|
||||
// cursor and any keyboard echo, which fights every frame we write. Putting the
|
||||
// active console into graphics mode stops it touching the framebuffer at all.
|
||||
@@ -88,21 +101,23 @@ func openFramebuffer(path string) (*framebuffer, error) {
|
||||
|
||||
fb := &framebuffer{
|
||||
file: f,
|
||||
w: int(vi[viXres]),
|
||||
h: int(vi[viYres]),
|
||||
pw: int(vi[viXres]),
|
||||
ph: int(vi[viYres]),
|
||||
w: int(vi[viYres]),
|
||||
h: int(vi[viXres]),
|
||||
stride: int(stride),
|
||||
rShift: uint(vi[viRedOffset]),
|
||||
gShift: uint(vi[viGreenOffset]),
|
||||
bShift: uint(vi[viBlueOffset]),
|
||||
}
|
||||
|
||||
fb.mem, err = unix.Mmap(int(f.Fd()), 0, fb.stride*fb.h,
|
||||
fb.mem, err = unix.Mmap(int(f.Fd()), 0, fb.stride*fb.ph,
|
||||
unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
|
||||
if err != nil {
|
||||
f.Close()
|
||||
return nil, fmt.Errorf("mmap: %w", err)
|
||||
}
|
||||
fb.back = make([]byte, fb.stride*fb.h)
|
||||
fb.back = make([]byte, fb.stride*fb.ph)
|
||||
|
||||
fb.tty, err = takeConsole()
|
||||
if err != nil {
|
||||
@@ -139,28 +154,28 @@ func (fb *framebuffer) fill(c rgb) {
|
||||
row[x+2] = byte(v >> 16)
|
||||
row[x+3] = byte(v >> 24)
|
||||
}
|
||||
for y := 0; y < fb.h; y++ {
|
||||
for y := 0; y < fb.ph; y++ {
|
||||
copy(fb.back[y*fb.stride:], row)
|
||||
}
|
||||
}
|
||||
|
||||
// One logical column is contiguous after the turn, so it fills a span at a time.
|
||||
func (fb *framebuffer) rect(x0, y0, w, h int, c rgb) {
|
||||
x1, y1 := min(x0+w, fb.w), min(y0+h, fb.h)
|
||||
x0, y0 = max(x0, 0), max(y0, 0)
|
||||
if x0 >= x1 || y0 >= y1 {
|
||||
return
|
||||
}
|
||||
v := fb.pixel(c)
|
||||
for y := y0; y < y0+h; y++ {
|
||||
if y < 0 || y >= fb.h {
|
||||
continue
|
||||
}
|
||||
base := y * fb.stride
|
||||
for x := x0; x < x0+w; x++ {
|
||||
if x < 0 || x >= fb.w {
|
||||
continue
|
||||
}
|
||||
o := base + x*4
|
||||
fb.back[o+0] = byte(v)
|
||||
fb.back[o+1] = byte(v >> 8)
|
||||
fb.back[o+2] = byte(v >> 16)
|
||||
fb.back[o+3] = byte(v >> 24)
|
||||
}
|
||||
span := make([]byte, (y1-y0)*4)
|
||||
for i := 0; i+4 <= len(span); i += 4 {
|
||||
span[i+0] = byte(v)
|
||||
span[i+1] = byte(v >> 8)
|
||||
span[i+2] = byte(v >> 16)
|
||||
span[i+3] = byte(v >> 24)
|
||||
}
|
||||
for x := x0; x < x1; x++ {
|
||||
copy(fb.back[fb.offset(x, y1-1):], span)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +184,7 @@ func (fb *framebuffer) blend(x, y int, c rgb, cov uint8) {
|
||||
if x < 0 || y < 0 || x >= fb.w || y >= fb.h || cov == 0 {
|
||||
return
|
||||
}
|
||||
o := y*fb.stride + x*4
|
||||
o := fb.offset(x, y)
|
||||
if cov == 255 {
|
||||
v := fb.pixel(c)
|
||||
fb.back[o+0] = byte(v)
|
||||
|
||||
Reference in New Issue
Block a user