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 }