mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
107 lines
2.4 KiB
Go
107 lines
2.4 KiB
Go
package console
|
|
|
|
import (
|
|
"reflect"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
clearColor = Black
|
|
clearChar = byte(' ')
|
|
)
|
|
|
|
// Vga implements an EGA-compatible text console. At the moment, it uses the
|
|
// ega console physical address as its outpucons. After implementing a memory
|
|
// allocator, each console will use its own framebuffer while the active console
|
|
// will periodically sync its internal buffer with the physical screen buffer.
|
|
type Vga struct {
|
|
width uint16
|
|
height uint16
|
|
|
|
fb []uint16
|
|
}
|
|
|
|
// Init sets up the console.
|
|
func (cons *Vga) Init() {
|
|
cons.width = 80
|
|
cons.height = 25
|
|
|
|
// Set up our frame buffer object by creating a fake slice object pointing
|
|
// to the physical address of the screen buffer.
|
|
if cons.fb != nil {
|
|
return
|
|
}
|
|
|
|
cons.fb = *(*[]uint16)(unsafe.Pointer(&reflect.SliceHeader{
|
|
Len: int(cons.width * cons.height),
|
|
Cap: int(cons.width * cons.height),
|
|
Data: uintptr(0xB8000),
|
|
}))
|
|
}
|
|
|
|
// Clear clears the specified rectangular region
|
|
func (cons *Vga) Clear(x, y, width, height uint16) {
|
|
var (
|
|
attr = uint16((clearColor << 4) | clearColor)
|
|
clr = attr | uint16(clearChar)
|
|
rowOffset, colOffset uint16
|
|
)
|
|
|
|
// clip rectangle
|
|
if x >= cons.width {
|
|
x = cons.width
|
|
}
|
|
if y >= cons.height {
|
|
y = cons.height
|
|
}
|
|
|
|
if x+width > cons.width {
|
|
width = cons.width - x
|
|
}
|
|
if y+height > cons.height {
|
|
height = cons.height - y
|
|
}
|
|
|
|
rowOffset = (y * cons.width) + x
|
|
for ; height > 0; height, rowOffset = height-1, rowOffset+cons.width {
|
|
for colOffset = rowOffset; colOffset < rowOffset+width; colOffset++ {
|
|
cons.fb[colOffset] = clr
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dimensions returns the console width and height in characters.
|
|
func (cons *Vga) Dimensions() (uint16, uint16) {
|
|
return cons.width, cons.height
|
|
}
|
|
|
|
// Scroll a particular number of lines to the specified direction.
|
|
func (cons *Vga) Scroll(dir ScrollDir, lines uint16) {
|
|
if lines == 0 || lines > cons.height {
|
|
return
|
|
}
|
|
|
|
var i uint16
|
|
offset := lines * cons.width
|
|
|
|
switch dir {
|
|
case Up:
|
|
for ; i < (cons.height-lines)*cons.width; i++ {
|
|
cons.fb[i] = cons.fb[i+offset]
|
|
}
|
|
case Down:
|
|
for i = cons.height*cons.width - 1; i >= lines*cons.width; i-- {
|
|
cons.fb[i] = cons.fb[i-offset]
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write a char to the specified location.
|
|
func (cons *Vga) Write(ch byte, attr Attr, x, y uint16) {
|
|
if x >= cons.width || y >= cons.height {
|
|
return
|
|
}
|
|
|
|
cons.fb[(y*cons.width)+x] = (uint16(attr) << 8) | uint16(ch)
|
|
}
|