basic colour rendering

This commit is contained in:
Liam Galvin 2018-07-01 16:29:14 +01:00
parent 726bfe6531
commit b0c60e7336
7 changed files with 349 additions and 62 deletions

View File

@ -2,29 +2,111 @@ package gui
import (
v41 "github.com/4ydx/gltext/v4.1"
"github.com/go-gl/gl/v4.1-core/gl"
"github.com/go-gl/mathgl/mgl32"
)
type Cell struct {
text *v41.Text
text *v41.Text
vao uint32
vbo uint32
cv uint32
colourAttr uint32
points []float32
colour [3]float32
}
func NewCell(font *v41.Font, x float32, y float32, w float32, h float32) Cell {
func (gui *GUI) NewCell(font *v41.Font, x float32, y float32, w float32, h float32, colourAttr uint32) Cell {
cell := Cell{
text: v41.NewText(font, 1.0, 1.1),
text: v41.NewText(font, 1.0, 1.1),
colourAttr: colourAttr,
}
cell.text.SetPosition(mgl32.Vec2{x, y})
x = (x - (w / 2)) / (float32(gui.width) / 2)
y = (y - (h / 2)) / (float32(gui.height) / 2)
w = (w / float32(gui.width/2))
h = (h / float32(gui.height/2))
cell.points = []float32{
x, y + h, 0,
x, y, 0,
x + w, y, 0,
x, y + h, 0,
x + w, y + h, 0,
x + w, y, 0,
}
cell.makeVao()
return cell
}
func (cell *Cell) Draw() {
func (cell *Cell) SetFgColour(r, g, b float32) {
if cell.text != nil {
cell.text.SetColor(mgl32.Vec3{r, g, b})
}
}
func (cell *Cell) SetBgColour(r float32, g float32, b float32) {
if cell.colour[0] == r && cell.colour[1] == g && cell.colour[2] == b {
return
}
cell.colour = [3]float32{r, g, b}
cell.Clean()
cell.makeVao()
}
func (cell *Cell) Clean() {
gl.DeleteVertexArrays(1, &cell.vao)
gl.DeleteBuffers(1, &cell.vbo)
}
func (cell *Cell) makeVao() {
gl.GenBuffers(1, &cell.vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, cell.vbo)
gl.BufferData(gl.ARRAY_BUFFER, 4*len(cell.points), gl.Ptr(cell.points), gl.STATIC_DRAW)
gl.GenVertexArrays(1, &cell.vao)
gl.BindVertexArray(cell.vao)
gl.EnableVertexAttribArray(0)
gl.BindBuffer(gl.ARRAY_BUFFER, cell.vbo)
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)
// COLOUR
gl.GenBuffers(1, &cell.cv)
gl.BindBuffer(gl.ARRAY_BUFFER, cell.cv)
triColor := []float32{
cell.colour[0], cell.colour[1], cell.colour[2],
cell.colour[0], cell.colour[1], cell.colour[2],
cell.colour[0], cell.colour[1], cell.colour[2],
cell.colour[0], cell.colour[1], cell.colour[2],
cell.colour[0], cell.colour[1], cell.colour[2],
cell.colour[0], cell.colour[1], cell.colour[2],
}
gl.BufferData(gl.ARRAY_BUFFER, len(triColor)*4, gl.Ptr(triColor), gl.STATIC_DRAW)
gl.EnableVertexAttribArray(cell.colourAttr)
gl.VertexAttribPointer(cell.colourAttr, 3, gl.FLOAT, false, 0, gl.PtrOffset(0))
// END COLOUR
}
func (cell *Cell) DrawBg() {
gl.BindVertexArray(cell.vao)
gl.DrawArrays(gl.TRIANGLES, 0, 6)
}
func (cell *Cell) DrawText() {
if cell.text != nil {
cell.text.Draw()
}
}
func (cell *Cell) Show() {
@ -45,12 +127,6 @@ func (cell *Cell) SetRune(r rune) {
}
}
func (cell *Cell) SetColour(r float32, g float32, b float32) {
if cell.text != nil {
cell.text.SetColor(mgl32.Vec3{r, g, b})
}
}
func (cell *Cell) Release() {
if cell.text != nil {
cell.text.Release()

View File

@ -31,7 +31,7 @@ type GUI struct {
cells [][]Cell
cols int
rows int
capslock bool
colourAttr uint32
}
func New(config config.Config, terminal *terminal.Terminal, logger *zap.SugaredLogger) *GUI {
@ -63,7 +63,6 @@ func (gui *GUI) resize(w *glfw.Window, width int, height int) {
if gui.font != nil {
gui.font.ResizeWindow(float32(width), float32(height))
}
gl.Viewport(0, 0, int32(width), int32(height))
scaleMin, scaleMax := float32(1.0), float32(1.1)
text := v41.NewText(gui.font, scaleMin, scaleMax)
@ -105,18 +104,12 @@ func (gui *GUI) updateTexts() {
}
if c.IsHidden() {
gui.cells[row][col].Hide()
// debug
//gui.texts[row][col].SetColor(c.GetColourVec())
//gui.texts[row][col].SetString("?")
//gui.texts[row][col].Show()
// end debug
continue
}
gui.cells[row][col].SetColour(c.GetColour())
gui.cells[row][col].SetFgColour(c.GetFgColour())
gui.cells[row][col].SetBgColour(c.GetBgColour())
gui.cells[row][col].SetRune(c.GetRune())
gui.cells[row][col].Show()
@ -141,7 +134,7 @@ func (gui *GUI) createTexts() {
x := ((float32(col) * gui.charWidth) - (float32(gui.width) / 2)) + (gui.charWidth / 2)
y := -(((float32(row) * gui.charHeight) - (float32(gui.height) / 2)) + (gui.charHeight / 2))
cells[row] = append(cells[row], NewCell(gui.font, x, y, gui.charWidth, gui.charHeight))
cells[row] = append(cells[row], gui.NewCell(gui.font, x, y, gui.charWidth, gui.charHeight, gui.colourAttr))
}
}
}
@ -151,6 +144,10 @@ func (gui *GUI) createTexts() {
gui.updateTexts()
}
func (gui *GUI) Close() {
gui.window.SetShouldClose(true)
}
func (gui *GUI) Render() error {
gui.logger.Debugf("Locking OS thread...")
@ -170,6 +167,9 @@ func (gui *GUI) Render() error {
return fmt.Errorf("Failed to initialise OpenGL: %s", err)
}
gui.colourAttr = uint32(gl.GetAttribLocation(program, gl.Str("inColour\x00")))
gl.BindFragDataLocation(program, 0, gl.Str("outColour\x00"))
gui.logger.Debugf("Loading font...")
//gui.font, err = gui.loadFont("/usr/share/fonts/nerd-fonts-complete/ttf/Roboto Mono Nerd Font Complete.ttf", 12)
if err := gui.loadFont("./fonts/CamingoCode-Regular.ttf", 12); err != nil {
@ -182,8 +182,6 @@ func (gui *GUI) Render() error {
w, h := gui.window.GetSize()
gui.resize(gui.window, w, h)
gl.Viewport(0, 0, int32(gui.width), int32(gui.height))
gui.logger.Debugf("Starting pty read handling...")
updateChan := make(chan bool, 1024)
@ -191,7 +189,13 @@ func (gui *GUI) Render() error {
gui.terminal.OnUpdate(func() {
updateChan <- true
})
go gui.terminal.Read()
go func() {
err := gui.terminal.Read()
if err != nil {
gui.logger.Errorf("Read from pty failed: %s", err)
}
gui.Close()
}()
text := v41.NewText(gui.font, 1.0, 1.1)
text.SetString("")
@ -209,6 +213,8 @@ func (gui *GUI) Render() error {
gui.logger.Debugf("Starting render...")
// todo set bg colour
//bgColour := gui.terminal.colourScheme.DefaultBgColor
gl.ClearColor(0.1, 0.1, 0.1, 1.0)
for !gui.window.ShouldClose() {
@ -232,6 +238,8 @@ func (gui *GUI) Render() error {
if updateRequired {
gl.Viewport(0, 0, int32(gui.width), int32(gui.height))
gui.updateTexts()
// Render the string.
@ -243,7 +251,14 @@ func (gui *GUI) Render() error {
for row := 0; row < rows; row++ {
for col := 0; col < cols; col++ {
gui.cells[row][col].Draw()
gui.cells[row][col].DrawBg()
}
}
for row := 0; row < rows; row++ {
for col := 0; col < cols; col++ {
gui.cells[row][col].DrawText()
}
}
@ -320,7 +335,21 @@ func (gui *GUI) createProgram() (uint32, error) {
}
gui.logger.Infof("OpenGL version %s", gl.GoStr(gl.GetString(gl.VERSION)))
gui.logger.Debugf("Compiling shaders...")
vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
if err != nil {
return 0, err
}
fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
if err != nil {
return 0, err
}
prog := gl.CreateProgram()
gl.AttachShader(prog, vertexShader)
gl.AttachShader(prog, fragmentShader)
gl.LinkProgram(prog)
return prog, nil

53
gui/shapes.go Normal file
View File

@ -0,0 +1,53 @@
package gui
import (
"fmt"
"strings"
"github.com/go-gl/gl/v4.1-core/gl" // OR: github.com/go-gl/gl/v2.1/gl
)
const (
vertexShaderSource = `
#version 410
in vec3 vp;
attribute vec3 inColour;
smooth out vec3 theColour;
void main() {
gl_Position = vec4(vp, 1.0);
theColour = inColour;
}
` + "\x00"
fragmentShaderSource = `
#version 410
smooth in vec3 theColour;
out vec4 outColour;
void main() {
outColour = vec4(theColour, 1.0);
}
` + "\x00"
)
func compileShader(source string, shaderType uint32) (uint32, error) {
shader := gl.CreateShader(shaderType)
csources, free := gl.Strs(source)
gl.ShaderSource(shader, 1, csources, nil)
free()
gl.CompileShader(shader)
var status int32
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
if status == gl.FALSE {
var logLength int32
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
log := strings.Repeat("\x00", int(logLength+1))
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
return 0, fmt.Errorf("failed to compile %v: %v", source, log)
}
return shader, nil
}

View File

@ -37,7 +37,7 @@ func main() {
}
sugaredLogger.Infof("Creating terminal...")
terminal := terminal.New(pty, sugaredLogger)
terminal := terminal.New(pty, sugaredLogger, terminal.DefaultColourScheme)
/*
go func() {
time.Sleep(time.Second * 1)

View File

@ -1,11 +1,19 @@
package terminal
import "github.com/go-gl/mathgl/mgl32"
type Cell struct {
r rune
wrapper bool
isWrapped bool
r rune
attr CellAttributes
}
type CellAttributes struct {
FgColour [3]float32
BgColour [3]float32
Bold bool
Dim bool
Underline bool
Blink bool
Reverse bool
Hidden bool
}
func (cell *Cell) GetRune() rune {
@ -13,28 +21,19 @@ func (cell *Cell) GetRune() rune {
}
func (cell *Cell) IsHidden() bool {
return cell.r == 0
return cell.attr.Hidden
}
func (cell *Cell) GetColour() (r float32, g float32, b float32) {
if cell.wrapper {
return 0, 1, 0
func (cell *Cell) GetFgColour() (r float32, g float32, b float32) {
if cell.attr.Reverse {
return cell.attr.BgColour[0], cell.attr.BgColour[1], cell.attr.BgColour[2]
}
if cell.isWrapped {
return 1, 1, 0
}
if cell.IsHidden() {
return 0, 0, 1
}
return 1, 1, 1
return cell.attr.FgColour[0], cell.attr.FgColour[1], cell.attr.FgColour[2]
}
func (cell *Cell) GetColourVec() mgl32.Vec3 {
r, g, b := cell.GetColour()
return mgl32.Vec3{r, g, b}
func (cell *Cell) GetBgColour() (r float32, g float32, b float32) {
if cell.attr.Reverse {
return cell.attr.FgColour[0], cell.attr.FgColour[1], cell.attr.FgColour[2]
}
return cell.attr.BgColour[0], cell.attr.BgColour[1], cell.attr.BgColour[2]
}

77
terminal/colours.go Normal file
View File

@ -0,0 +1,77 @@
package terminal
type ColourScheme struct {
DefaultFg [3]float32
BlackFg [3]float32
RedFg [3]float32
GreenFg [3]float32
YellowFg [3]float32
BlueFg [3]float32
MagentaFg [3]float32
CyanFg [3]float32
LightGreyFg [3]float32
DarkGreyFg [3]float32
LightRedFg [3]float32
LightGreenFg [3]float32
LightYellowFg [3]float32
LightBlueFg [3]float32
LightMagentaFg [3]float32
LightCyanFg [3]float32
WhiteFg [3]float32
DefaultBg [3]float32
BlackBg [3]float32
RedBg [3]float32
GreenBg [3]float32
YellowBg [3]float32
BlueBg [3]float32
MagentaBg [3]float32
CyanBg [3]float32
LightGreyBg [3]float32
DarkGreyBg [3]float32
LightRedBg [3]float32
LightGreenBg [3]float32
LightYellowBg [3]float32
LightBlueBg [3]float32
LightMagentaBg [3]float32
LightCyanBg [3]float32
WhiteBg [3]float32
}
var DefaultColourScheme = ColourScheme{
//fg
DefaultFg: [3]float32{1, 1, 1},
BlackFg: [3]float32{0, 0, 0},
RedFg: [3]float32{1, 0, 0},
GreenFg: [3]float32{0, 1, 0},
YellowFg: [3]float32{1, 1, 0},
BlueFg: [3]float32{0, 0, 1},
MagentaFg: [3]float32{1, 0, 1},
CyanFg: [3]float32{0, 1, 1},
LightGreyFg: [3]float32{0.7, 0.7, 0.7},
DarkGreyFg: [3]float32{0.3, 0.3, 0.3},
LightRedFg: [3]float32{1, 0.5, 0.5},
LightGreenFg: [3]float32{0.5, 1, 0.5},
LightYellowFg: [3]float32{1, 1, 0.5},
LightBlueFg: [3]float32{0.5, 0.5, 1},
LightMagentaFg: [3]float32{1, 0.5, 1},
LightCyanFg: [3]float32{0.5, 1, 1},
WhiteFg: [3]float32{1, 1, 1},
// bg
DefaultBg: [3]float32{0.1, 0.1, 0.1},
BlackBg: [3]float32{0, 0, 0},
RedBg: [3]float32{1, 0, 0},
GreenBg: [3]float32{0, 1, 0},
YellowBg: [3]float32{1, 1, 0},
BlueBg: [3]float32{0, 0, 1},
MagentaBg: [3]float32{1, 0, 1},
CyanBg: [3]float32{0, 1, 1},
LightGreyBg: [3]float32{0.7, 0.7, 0.7},
DarkGreyBg: [3]float32{0.3, 0.3, 0.3},
LightRedBg: [3]float32{1, 0.5, 0.5},
LightGreenBg: [3]float32{0.5, 1, 0.5},
LightYellowBg: [3]float32{1, 1, 0.5},
LightBlueBg: [3]float32{0.5, 0.5, 1},
LightMagentaBg: [3]float32{1, 0.5, 1},
LightCyanBg: [3]float32{0.5, 1, 1},
WhiteBg: [3]float32{1, 1, 1},
}

View File

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"strconv"
"strings"
"sync"
"syscall"
"unsafe"
@ -12,14 +13,17 @@ import (
)
type Terminal struct {
lines []Line // lines, where 0 is earliest, n is latest
position Position // line and col
lock sync.Mutex
pty *os.File
logger *zap.SugaredLogger
title string
onUpdate []func()
size Winsize
lines []Line // lines, where 0 is earliest, n is latest
position Position // line and col
lock sync.Mutex
pty *os.File
logger *zap.SugaredLogger
title string
onUpdate []func()
size Winsize
colourScheme ColourScheme
cellAttr CellAttributes
defaultCellAttr CellAttributes
}
type Line struct {
@ -84,14 +88,23 @@ type Position struct {
Col int
}
func New(pty *os.File, logger *zap.SugaredLogger) *Terminal {
func New(pty *os.File, logger *zap.SugaredLogger, colourScheme ColourScheme) *Terminal {
defaultCellAttr := CellAttributes{
FgColour: colourScheme.DefaultFg,
BgColour: colourScheme.DefaultBg,
}
return &Terminal{
lines: []Line{
NewLine(),
},
pty: pty,
logger: logger,
onUpdate: []func(){},
pty: pty,
logger: logger,
onUpdate: []func(){},
cellAttr: defaultCellAttr,
defaultCellAttr: defaultCellAttr,
colourScheme: colourScheme,
}
}
@ -225,6 +238,42 @@ func (terminal *Terminal) Read() error {
}
case byte('m'):
// SGR: colour and shit
sgr := string(params)
sgrParams := strings.Split(sgr, ";")
for i := range sgrParams {
param := sgrParams[i]
switch param {
case "0":
terminal.cellAttr = terminal.defaultCellAttr
case "1":
terminal.cellAttr.Bold = true
case "2":
terminal.cellAttr.Dim = true
case "4":
terminal.cellAttr.Underline = true
case "5":
terminal.cellAttr.Blink = true
case "7":
terminal.cellAttr.Reverse = true
case "8":
terminal.cellAttr.Hidden = true
case "21":
terminal.cellAttr.Bold = false
case "22":
terminal.cellAttr.Dim = false
case "24":
terminal.cellAttr.Underline = false
case "25":
terminal.cellAttr.Blink = false
case "27":
terminal.cellAttr.Reverse = false
case "28":
terminal.cellAttr.Hidden = false
case "39":
}
}
terminal.logger.Debugf("SGR params %#v intermediate %#v", params, intermediate)
default:
b = <-buffer
terminal.logger.Debugf("Unknown CSI control sequence: 0x%02X (%s)", final, string([]byte{final}))
@ -251,6 +300,8 @@ func (terminal *Terminal) Read() error {
default:
terminal.logger.Debugf("Unknown OSC control sequence: 0x%02X", b)
}
case byte('c'):
terminal.logger.Errorf("RIS not yet supported")
default:
terminal.logger.Debugf("Unknown control sequence: 0x%02X", b)
}
@ -285,6 +336,7 @@ func (terminal *Terminal) Read() error {
n, err := terminal.pty.Read(readBytes)
if err != nil {
terminal.logger.Errorf("Failed to read from pty: %s", err)
return err
}
if len(readBytes) > 0 {
readBytes = readBytes[:n]
@ -355,6 +407,7 @@ func (terminal *Terminal) setRuneAtPos(pos Position, r rune) error {
line.Cells = append(line.Cells, Cell{})
}
line.Cells[pos.Col].attr = terminal.cellAttr
line.Cells[pos.Col].r = r
return nil
}