mirror of https://github.com/liamg/aminal.git
things
This commit is contained in:
parent
5889d744f9
commit
5e2c2ca690
48
README.md
48
README.md
|
@ -52,33 +52,27 @@ Ensure you have your latest graphics card drivers installed before use.
|
||||||
| Mouse interaction | |
|
| Mouse interaction | |
|
||||||
| Sweet render effects | |
|
| Sweet render effects | |
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Raft looks for a config file in the following places: `~/.raft.yml`, `~/.config/raft.yml` (earlier in the list prioritised).
|
|
||||||
|
|
||||||
Example config:
|
|
||||||
```
|
|
||||||
debug: False
|
|
||||||
```
|
|
||||||
|
|
||||||
The following options are available:
|
|
||||||
|
|
||||||
| Name | Type | Default |Description |
|
|
||||||
|---------------|---------|---------|-----------------------|
|
|
||||||
| debug | bool | False | Enables debug logging
|
|
||||||
|
|
||||||
|
|
||||||
## Flags
|
|
||||||
|
|
||||||
| Name | Type | Default |Description |
|
|
||||||
|------------------|---------|---------|-----------------------|
|
|
||||||
| --debug | bool | False | Enables debug logging |
|
|
||||||
| --ignore-config | bool | False | Ignores user config files and uses defaults
|
|
||||||
| --always-repaint | bool | False | Redraw the terminal constantly, even when no changes have been made
|
|
||||||
|
|
||||||
## Keyboard Shortcuts
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
| Operation | Key(s) |
|
| Operation | Key(s) |
|
||||||
|-----------|---------------------|
|
|--------------------|---------------------|
|
||||||
| Paste | ctrl + shift + v
|
| Paste | ctrl + shift + v
|
||||||
|
| Interrupt (SIGINT) | ctrl + c
|
||||||
|
| Suspend | ctrl + s
|
||||||
|
| Resume | ctrl + q
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Raft looks for a config file in `~/.raft.toml`, and will write one there the first time it runs, if it doesn't already exist.
|
||||||
|
|
||||||
|
You can ignore the config and use defauls by specifying `--ignore-config` as a CLI flag.
|
||||||
|
|
||||||
|
### Config Options/CLI Flags
|
||||||
|
|
||||||
|
| CLI Flag | Config Section | Config Name | Type | Default | Description |
|
||||||
|
|--------------------|---------------------|------------------------|---------|--------------|-------------|
|
||||||
|
| --debug | _root_ | debug | boolean | false | Enable debug mode, with debug logging and debug info terminal overlay.
|
||||||
|
| --slomo | _root_ | slomo | boolean | false | Enable slomo mode, delay the handling of each incoming byte (or escape sequence) from the pty by 100ms. Useful for debugging.
|
||||||
|
| --always-repaint | rendering | always_repaint | boolean | false | Redraw the terminal GUI constantly, even when no changes have occurred.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,19 +21,16 @@ func newCell() Cell {
|
||||||
return Cell{}
|
return Cell{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cell *Cell) Attr() CellAttributes {
|
||||||
|
return cell.attr
|
||||||
|
}
|
||||||
|
|
||||||
func (cell *Cell) Rune() rune {
|
func (cell *Cell) Rune() rune {
|
||||||
if cell.r == 0 {
|
|
||||||
return '~'
|
|
||||||
}
|
|
||||||
return cell.r
|
return cell.r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *Cell) Fg() [3]float32 {
|
func (cell *Cell) Fg() [3]float32 {
|
||||||
if cell.r == 0 {
|
return cell.attr.FgColour
|
||||||
return [3]float32{0.5, 0.5, 0.5}
|
|
||||||
}
|
|
||||||
return [3]float32{0.9, 0.9, 0.9} // @todo fix this
|
|
||||||
//return cell.attr.FgColour
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *Cell) Bg() [3]float32 {
|
func (cell *Cell) Bg() [3]float32 {
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"math"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Colour [3]float32
|
||||||
|
|
||||||
|
func (c *Colour) UnmarshalText(data []byte) error {
|
||||||
|
|
||||||
|
hexStr := string(data)
|
||||||
|
|
||||||
|
if strings.HasPrefix(hexStr, "#") {
|
||||||
|
hexStr = hexStr[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(hexStr) != 6 {
|
||||||
|
return fmt.Errorf("Invalid colour format. Should be like #ffffff")
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := hex.DecodeString(hexStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
c[0] = float32(bytes[0]) / 255
|
||||||
|
c[1] = float32(bytes[1]) / 255
|
||||||
|
c[2] = float32(bytes[2]) / 255
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Colour) MarshalText() (text []byte, err error) {
|
||||||
|
return []byte(fmt.Sprintf(
|
||||||
|
"#%02x%02x%02x",
|
||||||
|
uint8(math.Floor(float64(255*c[0]))),
|
||||||
|
uint8(math.Floor(float64(255*c[1]))),
|
||||||
|
uint8(math.Floor(float64(255*c[2]))),
|
||||||
|
)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ColourScheme struct {
|
||||||
|
Cursor Colour `toml:"cursor"`
|
||||||
|
DefaultFg Colour `toml:"default_fg"`
|
||||||
|
BlackFg Colour `toml:"black_fg"`
|
||||||
|
RedFg Colour `toml:"red_fg"`
|
||||||
|
GreenFg Colour `toml:"green_fg"`
|
||||||
|
YellowFg Colour `toml:"yellow_fg"`
|
||||||
|
BlueFg Colour `toml:"blue_fg"`
|
||||||
|
MagentaFg Colour `toml:"magenta_fg"`
|
||||||
|
CyanFg Colour `toml:"cyan_fg"`
|
||||||
|
LightGreyFg Colour `toml:"light_grey_fg"`
|
||||||
|
DarkGreyFg Colour `toml:"dark_grey_fg"`
|
||||||
|
LightRedFg Colour `toml:"light_red_fg"`
|
||||||
|
LightGreenFg Colour `toml:"light_green_fg"`
|
||||||
|
LightYellowFg Colour `toml:"light_yellow_fg"`
|
||||||
|
LightBlueFg Colour `toml:"light_blue_fg"`
|
||||||
|
LightMagentaFg Colour `toml:"light_magenta_fg"`
|
||||||
|
LightCyanFg Colour `toml:"light_cyan_fg"`
|
||||||
|
WhiteFg Colour `toml:"white_fg"`
|
||||||
|
DefaultBg Colour `toml:"default_bg"`
|
||||||
|
BlackBg Colour `toml:"black_bg"`
|
||||||
|
RedBg Colour `toml:"red_bg"`
|
||||||
|
GreenBg Colour `toml:"green_bg"`
|
||||||
|
YellowBg Colour `toml:"yellow_bg"`
|
||||||
|
BlueBg Colour `toml:"blue_bg"`
|
||||||
|
MagentaBg Colour `toml:"magenta_bg"`
|
||||||
|
CyanBg Colour `toml:"cyan_bg"`
|
||||||
|
LightGreyBg Colour `toml:"light_grey_bg"`
|
||||||
|
DarkGreyBg Colour `toml:"dark_grey_bg"`
|
||||||
|
LightRedBg Colour `toml:"light_red_bg"`
|
||||||
|
LightGreenBg Colour `toml:"light_green_bg"`
|
||||||
|
LightYellowBg Colour `toml:"light_yellow_bg"`
|
||||||
|
LightBlueBg Colour `toml:"light_blue_bg"`
|
||||||
|
LightMagentaBg Colour `toml:"light_magenta_bg"`
|
||||||
|
LightCyanBg Colour `toml:"light_cyan_bg"`
|
||||||
|
WhiteBg Colour `toml:"white_bg"`
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestColourTomlEncoding(t *testing.T) {
|
||||||
|
target := struct {
|
||||||
|
Orange Colour `toml:"colour"`
|
||||||
|
}{
|
||||||
|
Orange: Colour([3]float32{1, 0.5, 0}),
|
||||||
|
}
|
||||||
|
var buf bytes.Buffer
|
||||||
|
e := toml.NewEncoder(&buf)
|
||||||
|
err := e.Encode(target)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.Equal(t, `colour = "#ff7f00"
|
||||||
|
`, buf.String())
|
||||||
|
|
||||||
|
}
|
||||||
|
func TestColourTomlUnmarshalling(t *testing.T) {
|
||||||
|
target := struct {
|
||||||
|
Purple Colour `toml:"colour"`
|
||||||
|
}{}
|
||||||
|
err := toml.Unmarshal([]byte(`colour = "#7f00ff"`), &target)
|
||||||
|
require.Nil(t, err)
|
||||||
|
assert.InDelta(t, 0.5, target.Purple[0], 0.01)
|
||||||
|
assert.InDelta(t, 0.0, target.Purple[1], 0.01)
|
||||||
|
assert.InDelta(t, 1.0, target.Purple[2], 0.01)
|
||||||
|
}
|
105
config/config.go
105
config/config.go
|
@ -1,105 +1,34 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
yaml "gopkg.in/yaml.v2"
|
"bytes"
|
||||||
|
|
||||||
|
"github.com/BurntSushi/toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
DebugMode bool `yaml:"debug"`
|
DebugMode bool `toml:"debug"`
|
||||||
ColourScheme ColourScheme
|
Rendering RenderingConfig `toml:"rendering"`
|
||||||
Rendering RenderingConfig `yaml:"rendering"`
|
Slomo bool `toml:"slomo"`
|
||||||
Slomo bool `yaml:"slomo"`
|
ColourScheme ColourScheme `toml:"colours"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RenderingConfig struct {
|
type RenderingConfig struct {
|
||||||
AlwaysRepaint bool `yaml:"always_repaint"`
|
AlwaysRepaint bool `toml:"always_repaint"`
|
||||||
}
|
|
||||||
|
|
||||||
var DefaultConfig = Config{
|
|
||||||
DebugMode: false,
|
|
||||||
ColourScheme: DefaultColourScheme,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Parse(data []byte) (*Config, error) {
|
func Parse(data []byte) (*Config, error) {
|
||||||
c := DefaultConfig
|
c := DefaultConfig
|
||||||
err := yaml.Unmarshal(data, &c)
|
err := toml.Unmarshal(data, &c)
|
||||||
return &c, err
|
return &c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
type ColourScheme struct {
|
func (c *Config) Encode() ([]byte, error) {
|
||||||
Cursor [3]float32
|
var buf bytes.Buffer
|
||||||
DefaultFg [3]float32
|
e := toml.NewEncoder(&buf)
|
||||||
BlackFg [3]float32
|
err := e.Encode(c)
|
||||||
RedFg [3]float32
|
if err != nil {
|
||||||
GreenFg [3]float32
|
return nil, err
|
||||||
YellowFg [3]float32
|
}
|
||||||
BlueFg [3]float32
|
return buf.Bytes(), nil
|
||||||
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{
|
|
||||||
Cursor: [3]float32{0.8, 0.8, 0.8},
|
|
||||||
//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},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
var DefaultConfig = Config{
|
||||||
|
DebugMode: false,
|
||||||
|
ColourScheme: ColourScheme{
|
||||||
|
Cursor: [3]float32{0.8, 0.8, 0.8},
|
||||||
|
//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},
|
||||||
|
},
|
||||||
|
}
|
|
@ -106,7 +106,7 @@ func (gui *GUI) Render() error {
|
||||||
return fmt.Errorf("Failed to load font: %s", err)
|
return fmt.Errorf("Failed to load font: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gui.renderer = NewOpenGLRenderer(gui.font, gui.fontScale, 0, 0, gui.width, gui.height)
|
gui.renderer = NewOpenGLRenderer(gui.config, gui.font, gui.fontScale, 0, 0, gui.width, gui.height)
|
||||||
|
|
||||||
gui.window.SetFramebufferSizeCallback(gui.resize)
|
gui.window.SetFramebufferSizeCallback(gui.resize)
|
||||||
gui.window.SetKeyCallback(gui.key)
|
gui.window.SetKeyCallback(gui.key)
|
||||||
|
@ -137,7 +137,7 @@ func (gui *GUI) Render() error {
|
||||||
//glfw.SwapInterval(1)
|
//glfw.SwapInterval(1)
|
||||||
|
|
||||||
gl.ClearColor(
|
gl.ClearColor(
|
||||||
gui.config.ColourScheme.DefaultBg[0],
|
1.0, //gui.config.ColourScheme.DefaultBg[0],
|
||||||
gui.config.ColourScheme.DefaultBg[1],
|
gui.config.ColourScheme.DefaultBg[1],
|
||||||
gui.config.ColourScheme.DefaultBg[2],
|
gui.config.ColourScheme.DefaultBg[2],
|
||||||
1.0,
|
1.0,
|
||||||
|
|
147
gui/renderer.go
147
gui/renderer.go
|
@ -4,8 +4,10 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
|
"github.com/go-gl/gl/all-core/gl"
|
||||||
"github.com/liamg/glfont"
|
"github.com/liamg/glfont"
|
||||||
"gitlab.com/liamg/raft/buffer"
|
"gitlab.com/liamg/raft/buffer"
|
||||||
|
"gitlab.com/liamg/raft/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Renderer interface {
|
type Renderer interface {
|
||||||
|
@ -27,9 +29,90 @@ type OpenGLRenderer struct {
|
||||||
termCols int
|
termCols int
|
||||||
termRows int
|
termRows int
|
||||||
cellPositions map[[2]int][2]float32
|
cellPositions map[[2]int][2]float32
|
||||||
|
rectangles map[[2]int]*rectangle
|
||||||
|
config config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewOpenGLRenderer(font *glfont.Font, fontScale int32, areaX int, areaY int, areaWidth int, areaHeight int) *OpenGLRenderer {
|
type rectangle struct {
|
||||||
|
vao uint32
|
||||||
|
vbo uint32
|
||||||
|
cv uint32
|
||||||
|
colourAttr uint32
|
||||||
|
colour [3]float32
|
||||||
|
points []float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *OpenGLRenderer) newRectangle(x float32, y float32) *rectangle {
|
||||||
|
|
||||||
|
x = (x - float32(r.areaWidth/2)) / float32(r.areaWidth/2)
|
||||||
|
y = -(y - float32(r.areaHeight/2)) / float32(r.areaHeight/2)
|
||||||
|
w := r.cellWidth / float32(r.areaWidth/2)
|
||||||
|
h := r.cellHeight / float32(r.areaHeight/2)
|
||||||
|
|
||||||
|
rect := &rectangle{
|
||||||
|
colour: [3]float32{0, 0, 1},
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.gen()
|
||||||
|
|
||||||
|
return rect
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rect *rectangle) gen() {
|
||||||
|
|
||||||
|
colour := []float32{
|
||||||
|
rect.colour[0], rect.colour[1], rect.colour[2],
|
||||||
|
rect.colour[0], rect.colour[1], rect.colour[2],
|
||||||
|
rect.colour[0], rect.colour[1], rect.colour[2],
|
||||||
|
rect.colour[0], rect.colour[1], rect.colour[2],
|
||||||
|
rect.colour[0], rect.colour[1], rect.colour[2],
|
||||||
|
rect.colour[0], rect.colour[1], rect.colour[2],
|
||||||
|
}
|
||||||
|
|
||||||
|
// SHAPE
|
||||||
|
gl.GenBuffers(1, &rect.vbo)
|
||||||
|
gl.BindBuffer(gl.ARRAY_BUFFER, rect.vbo)
|
||||||
|
gl.BufferData(gl.ARRAY_BUFFER, 4*len(rect.points), gl.Ptr(rect.points), gl.STATIC_DRAW)
|
||||||
|
|
||||||
|
gl.GenVertexArrays(1, &rect.vao)
|
||||||
|
gl.BindVertexArray(rect.vao)
|
||||||
|
gl.EnableVertexAttribArray(0)
|
||||||
|
|
||||||
|
gl.BindBuffer(gl.ARRAY_BUFFER, rect.vbo)
|
||||||
|
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil)
|
||||||
|
|
||||||
|
// colour
|
||||||
|
gl.GenBuffers(1, &rect.cv)
|
||||||
|
gl.BindBuffer(gl.ARRAY_BUFFER, rect.cv)
|
||||||
|
gl.BufferData(gl.ARRAY_BUFFER, len(colour)*4, gl.Ptr(colour), gl.STATIC_DRAW)
|
||||||
|
gl.EnableVertexAttribArray(rect.colourAttr)
|
||||||
|
gl.VertexAttribPointer(rect.colourAttr, 3, gl.FLOAT, false, 0, gl.PtrOffset(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rect *rectangle) setColour(colour [3]float32) {
|
||||||
|
if rect.colour == colour || true {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rect.Free()
|
||||||
|
rect.colour = colour
|
||||||
|
rect.gen()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (rect *rectangle) Free() {
|
||||||
|
gl.DeleteVertexArrays(1, &rect.vao)
|
||||||
|
gl.DeleteBuffers(1, &rect.vbo)
|
||||||
|
gl.DeleteBuffers(1, &rect.cv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOpenGLRenderer(config config.Config, font *glfont.Font, fontScale int32, areaX int, areaY int, areaWidth int, areaHeight int) *OpenGLRenderer {
|
||||||
r := &OpenGLRenderer{
|
r := &OpenGLRenderer{
|
||||||
areaWidth: areaWidth,
|
areaWidth: areaWidth,
|
||||||
areaHeight: areaHeight,
|
areaHeight: areaHeight,
|
||||||
|
@ -37,6 +120,8 @@ func NewOpenGLRenderer(font *glfont.Font, fontScale int32, areaX int, areaY int,
|
||||||
areaY: areaY,
|
areaY: areaY,
|
||||||
fontScale: fontScale,
|
fontScale: fontScale,
|
||||||
cellPositions: map[[2]int][2]float32{},
|
cellPositions: map[[2]int][2]float32{},
|
||||||
|
rectangles: map[[2]int]*rectangle{},
|
||||||
|
config: config,
|
||||||
}
|
}
|
||||||
r.SetFont(font)
|
r.SetFont(font)
|
||||||
return r
|
return r
|
||||||
|
@ -59,7 +144,7 @@ func (r *OpenGLRenderer) SetFontScale(fontScale int32) {
|
||||||
r.SetFont(r.font)
|
r.SetFont(r.font)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OpenGLRenderer) SetFont(font *glfont.Font) {
|
func (r *OpenGLRenderer) SetFont(font *glfont.Font) { // @todo check for monospace and return error if not?
|
||||||
r.font = font
|
r.font = font
|
||||||
r.verticalCellPadding = (0.3 * float32(r.fontScale))
|
r.verticalCellPadding = (0.3 * float32(r.fontScale))
|
||||||
r.cellWidth = font.Width(1, "X")
|
r.cellWidth = font.Width(1, "X")
|
||||||
|
@ -67,14 +152,15 @@ func (r *OpenGLRenderer) SetFont(font *glfont.Font) {
|
||||||
r.termCols = int(math.Floor(float64(float32(r.areaWidth) / r.cellWidth)))
|
r.termCols = int(math.Floor(float64(float32(r.areaWidth) / r.cellWidth)))
|
||||||
r.termRows = int(math.Floor(float64(float32(r.areaHeight) / r.cellHeight)))
|
r.termRows = int(math.Floor(float64(float32(r.areaHeight) / r.cellHeight)))
|
||||||
r.calculatePositions()
|
r.calculatePositions()
|
||||||
|
r.generateRectangles()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *OpenGLRenderer) calculatePositions() {
|
func (r *OpenGLRenderer) calculatePositions() {
|
||||||
for line := 0; line < r.termRows; line++ {
|
for line := 0; line < r.termRows; line++ {
|
||||||
for col := 0; col < r.termCols; col++ {
|
for col := 0; col < r.termCols; col++ {
|
||||||
// rounding to whole pixels makes everything nice
|
// rounding to whole pixels makes everything nice
|
||||||
x := float32(math.Floor(float64((float32(col) * r.cellWidth) + (r.cellWidth / 2))))
|
x := float32(math.Round(float64((float32(col) * r.cellWidth))))
|
||||||
y := float32(math.Floor(float64(
|
y := float32(math.Round(float64(
|
||||||
(float32(line) * r.cellHeight) + (r.cellHeight / 2) + r.verticalCellPadding,
|
(float32(line) * r.cellHeight) + (r.cellHeight / 2) + r.verticalCellPadding,
|
||||||
)))
|
)))
|
||||||
r.cellPositions[[2]int{col, line}] = [2]float32{x, y}
|
r.cellPositions[[2]int{col, line}] = [2]float32{x, y}
|
||||||
|
@ -82,19 +168,66 @@ func (r *OpenGLRenderer) calculatePositions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *OpenGLRenderer) generateRectangles() {
|
||||||
|
for line := 0; line < r.termRows; line++ {
|
||||||
|
for col := 0; col < r.termCols; col++ {
|
||||||
|
|
||||||
|
rect, ok := r.rectangles[[2]int{col, line}]
|
||||||
|
if ok {
|
||||||
|
rect.Free()
|
||||||
|
}
|
||||||
|
|
||||||
|
// rounding to whole pixels makes everything nice
|
||||||
|
x := float32(float64((float32(col) * r.cellWidth)))
|
||||||
|
y := float32(float64((float32(line) * r.cellHeight) + (r.cellHeight)))
|
||||||
|
r.rectangles[[2]int{col, line}] = r.newRectangle(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (r *OpenGLRenderer) DrawCell(cell *buffer.Cell, col int, row int) {
|
func (r *OpenGLRenderer) DrawCell(cell *buffer.Cell, col int, row int) {
|
||||||
|
|
||||||
if cell == nil {
|
if cell == nil || cell.Attr().Hidden || cell.Rune() == 0x00 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fg := cell.Fg()
|
var fg [3]float32
|
||||||
r.font.SetColor(fg[0], fg[1], fg[2], 1)
|
var bg [3]float32
|
||||||
|
|
||||||
|
if cell.Attr().Reverse {
|
||||||
|
fg = cell.Bg()
|
||||||
|
bg = cell.Fg()
|
||||||
|
} else {
|
||||||
|
fg = cell.Fg()
|
||||||
|
bg = cell.Bg()
|
||||||
|
}
|
||||||
|
|
||||||
|
var alpha float32 = 1
|
||||||
|
if cell.Attr().Dim {
|
||||||
|
alpha = 0.5
|
||||||
|
}
|
||||||
|
r.font.SetColor(fg[0], fg[1], fg[2], alpha)
|
||||||
|
|
||||||
pos, ok := r.cellPositions[[2]int{col, row}]
|
pos, ok := r.cellPositions[[2]int{col, row}]
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("Missing position data for cell at %d,%d", col, row))
|
panic(fmt.Sprintf("Missing position data for cell at %d,%d", col, row))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rect, ok := r.rectangles[[2]int{col, row}]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("Missing rectangle data for cell at %d,%d", col, row))
|
||||||
|
}
|
||||||
|
|
||||||
|
//rect.setColour(bg)
|
||||||
|
_ = bg
|
||||||
|
rect.setColour([3]float32{0, 0, 1})
|
||||||
|
|
||||||
|
gl.BindVertexArray(rect.vao)
|
||||||
|
gl.DrawArrays(gl.TRIANGLES, 0, 6)
|
||||||
|
|
||||||
|
if cell.Attr().Bold { // bold means draw text again one pixel to right, so it's fatter
|
||||||
|
r.font.Print(pos[0]+1, pos[1], 1, string(cell.Rune()))
|
||||||
|
}
|
||||||
r.font.Print(pos[0], pos[1], 1, string(cell.Rune()))
|
r.font.Print(pos[0], pos[1], 1, string(cell.Rune()))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
16
main.go
16
main.go
|
@ -21,6 +21,7 @@ func getConfig() config.Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
conf := loadConfigFile()
|
conf := loadConfigFile()
|
||||||
|
|
||||||
flag.BoolVar(&conf.DebugMode, "debug", conf.DebugMode, "Enable debug logging")
|
flag.BoolVar(&conf.DebugMode, "debug", conf.DebugMode, "Enable debug logging")
|
||||||
flag.BoolVar(&conf.Slomo, "slomo", conf.Slomo, "Render in slow motion (useful for debugging)")
|
flag.BoolVar(&conf.Slomo, "slomo", conf.Slomo, "Render in slow motion (useful for debugging)")
|
||||||
flag.BoolVar(&conf.Rendering.AlwaysRepaint, "always-repaint", conf.Rendering.AlwaysRepaint, "Always repaint the window, even when no changes have occurred")
|
flag.BoolVar(&conf.Rendering.AlwaysRepaint, "always-repaint", conf.Rendering.AlwaysRepaint, "Always repaint the window, even when no changes have occurred")
|
||||||
|
@ -37,8 +38,8 @@ func loadConfigFile() config.Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
places := []string{
|
places := []string{
|
||||||
fmt.Sprintf("%s/.raft.yml", home),
|
//fmt.Sprintf("%s/.config/raft.yml", home),
|
||||||
fmt.Sprintf("%s/.config/raft.yml", home),
|
fmt.Sprintf("%s/.raft.toml", home),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, place := range places {
|
for _, place := range places {
|
||||||
|
@ -51,6 +52,13 @@ func loadConfigFile() config.Config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if b, err := config.DefaultConfig.Encode(); err != nil {
|
||||||
|
fmt.Printf("Failed to encode config file: %s\n", err)
|
||||||
|
} else {
|
||||||
|
if err := ioutil.WriteFile(fmt.Sprintf("%s/.raft.toml", home), b, 0644); err != nil {
|
||||||
|
fmt.Printf("Failed to encode config file: %s\n", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
return config.DefaultConfig
|
return config.DefaultConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +69,9 @@ func getLogger(conf config.Config) (*zap.SugaredLogger, error) {
|
||||||
if conf.DebugMode {
|
if conf.DebugMode {
|
||||||
logger, err = zap.NewDevelopment()
|
logger, err = zap.NewDevelopment()
|
||||||
} else {
|
} else {
|
||||||
logger, err = zap.NewProduction()
|
loggerConfig := zap.NewProductionConfig()
|
||||||
|
loggerConfig.Encoding = "console"
|
||||||
|
logger, err = loggerConfig.Build()
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to create logger: %s", err)
|
return nil, fmt.Errorf("Failed to create logger: %s", err)
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
package terminal
|
|
||||||
|
|
||||||
type Cell struct {
|
|
||||||
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 (terminal *Terminal) NewCell() Cell {
|
|
||||||
return Cell{
|
|
||||||
attr: CellAttributes{
|
|
||||||
FgColour: terminal.config.ColourScheme.DefaultFg,
|
|
||||||
BgColour: terminal.config.ColourScheme.DefaultBg,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cell *Cell) GetRune() rune {
|
|
||||||
return cell.r
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cell *Cell) IsHidden() bool {
|
|
||||||
return cell.attr.Hidden
|
|
||||||
}
|
|
||||||
|
|
||||||
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]
|
|
||||||
}
|
|
||||||
return cell.attr.FgColour[0], cell.attr.FgColour[1], cell.attr.FgColour[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
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]
|
|
||||||
}
|
|
|
@ -28,11 +28,6 @@ type Terminal struct {
|
||||||
resumeChan chan bool
|
resumeChan chan bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Line struct {
|
|
||||||
Cells []Cell
|
|
||||||
wrapped bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type Winsize struct {
|
type Winsize struct {
|
||||||
Height uint16
|
Height uint16
|
||||||
Width uint16
|
Width uint16
|
||||||
|
|
Loading…
Reference in New Issue