github.com/jspc/eggos@v0.5.1-0.20221028160421-556c75c878a5/drivers/cga/fbcga/fbcga.go (about)

     1  package fbcga
     2  
     3  import (
     4  	"image"
     5  	"image/color"
     6  	"image/draw"
     7  
     8  	"github.com/jspc/eggos/drivers/vbe"
     9  
    10  	"golang.org/x/image/font"
    11  	"golang.org/x/image/font/basicfont"
    12  	"golang.org/x/image/font/inconsolata"
    13  	"golang.org/x/image/math/fixed"
    14  )
    15  
    16  const (
    17  	del = 0x7f
    18  	bs  = '\b'
    19  
    20  	twidth  = 80
    21  	theight = 25
    22  )
    23  
    24  var (
    25  	view   *vbe.View
    26  	face   *basicfont.Face
    27  	drawer *font.Drawer
    28  
    29  	foreColor = color.RGBA{199, 199, 199, 0}
    30  	backColor = color.Black
    31  
    32  	Backend = fbbackend{}
    33  )
    34  
    35  type fbbackend struct {
    36  	pos    int
    37  	cursor int
    38  	buffer [twidth * theight]byte
    39  }
    40  
    41  func (f *fbbackend) xy(pos int) (int, int) {
    42  	x, y := pos%twidth*face.Advance, (pos/twidth+1)*face.Height
    43  	if face.Left < 0 {
    44  		x += -face.Left
    45  	}
    46  	return x, y
    47  }
    48  
    49  func (f *fbbackend) glyphPos(pos int) fixed.Point26_6 {
    50  	x, y := f.xy(pos)
    51  	return fixed.Point26_6{X: fixed.I(x), Y: fixed.I(y)}
    52  }
    53  
    54  func (f *fbbackend) drawChar(pos int, c byte, overide bool) {
    55  	if c == 0 {
    56  		return
    57  	}
    58  	fpos := f.glyphPos(pos)
    59  	rect, _, _, _, _ := face.Glyph(fpos, rune(c))
    60  	if overide {
    61  		// clear old font
    62  		draw.Draw(drawer.Dst, rect, image.NewUniform(backColor), image.Point{}, draw.Src)
    63  	}
    64  	drawer.Dot = fpos
    65  	drawer.DrawBytes([]byte{c})
    66  	view.CommitRect(rect)
    67  }
    68  
    69  func (f *fbbackend) setChar(pos int, c byte) {
    70  	f.drawChar(pos, c, true)
    71  	f.buffer[pos] = c
    72  }
    73  
    74  func (f *fbbackend) scrollup(pos int) int {
    75  	copy(f.buffer[:], f.buffer[twidth:theight*twidth])
    76  	pos -= twidth
    77  	s := f.buffer[pos : theight*twidth]
    78  	for i := range s {
    79  		s[i] = 0
    80  	}
    81  	f.refresh()
    82  	return pos
    83  }
    84  
    85  func (f *fbbackend) refresh() {
    86  	rect := image.Rect(0, 0, twidth*face.Advance+face.Left, theight*face.Height+face.Descent)
    87  	draw.Draw(drawer.Dst, rect, image.NewUniform(backColor), image.Point{}, draw.Src)
    88  
    89  	for i := 0; i < theight; i++ {
    90  		y := (i + 1) * face.Height
    91  		drawer.Dot = fixed.Point26_6{X: fixed.I(0), Y: fixed.I(y)}
    92  		drawer.DrawBytes(f.buffer[i*twidth : (i+1)*twidth])
    93  	}
    94  	view.CommitRect(rect)
    95  }
    96  
    97  func (f *fbbackend) updateCursor(n int) {
    98  	old := f.cursor
    99  	ch := f.buffer[old]
   100  	f.drawChar(old, ch, true)
   101  
   102  	f.drawChar(n, '_', false)
   103  	f.cursor = n
   104  }
   105  
   106  func (f *fbbackend) SetPos(n int) {
   107  	f.pos = n
   108  	f.updateCursor(n)
   109  }
   110  
   111  func (f *fbbackend) GetPos() int {
   112  	return f.pos
   113  }
   114  
   115  func (f *fbbackend) WritePos(n int, ch byte) {
   116  	f.setChar(n, ch)
   117  }
   118  
   119  func (f *fbbackend) WriteByte(c byte) {
   120  	pos := f.GetPos()
   121  	switch c {
   122  	case '\n', '\r':
   123  		pos += twidth - pos%twidth
   124  	case bs, del:
   125  		if pos > 0 {
   126  			f.setChar(pos, ' ')
   127  			pos--
   128  			f.setChar(pos, ' ')
   129  		}
   130  	default:
   131  		f.setChar(pos, c)
   132  		pos++
   133  	}
   134  
   135  	// Scroll up
   136  	if pos/twidth >= theight {
   137  		pos = f.scrollup(pos)
   138  	}
   139  	f.setChar(pos, ' ')
   140  	f.SetPos(pos)
   141  }
   142  
   143  func Init() {
   144  	if !vbe.IsEnable() {
   145  		return
   146  	}
   147  	face = inconsolata.Regular8x16
   148  	// face = inconsolata.Bold8x16
   149  	view = vbe.DefaultView
   150  	drawer = &font.Drawer{
   151  		Dst:  view.Canvas(),
   152  		Src:  image.NewUniform(foreColor),
   153  		Face: face,
   154  	}
   155  }