mirror of https://github.com/liamg/aminal.git
finished sixel support
This commit is contained in:
parent
20c3c0cb14
commit
78d67302b4
38
README.md
38
README.md
|
@ -10,9 +10,14 @@ The project is experimental at the moment, so you probably won't want to rely on
|
||||||
|
|
||||||
Ensure you have your latest graphics card drivers installed before use.
|
Ensure you have your latest graphics card drivers installed before use.
|
||||||
|
|
||||||
|
Sixels are now supported.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## Aims
|
## Aims
|
||||||
|
|
||||||
- Full unicode support
|
- Unicode support
|
||||||
- OpenGL rendering
|
- OpenGL rendering
|
||||||
- Full customisation options
|
- Full customisation options
|
||||||
- True colour support
|
- True colour support
|
||||||
|
@ -23,6 +28,7 @@ Ensure you have your latest graphics card drivers installed before use.
|
||||||
- Resize logic that wraps/unwraps lines _correctly_
|
- Resize logic that wraps/unwraps lines _correctly_
|
||||||
- Bullshit graphical effects
|
- Bullshit graphical effects
|
||||||
- Multi platform support
|
- Multi platform support
|
||||||
|
- Sixel support
|
||||||
|
|
||||||
## What isn't supported?
|
## What isn't supported?
|
||||||
|
|
||||||
|
@ -32,13 +38,6 @@ Ensure you have your latest graphics card drivers installed before use.
|
||||||
<img alt="Overheating" src="https://imgs.xkcd.com/comics/workflow.png"/>
|
<img alt="Overheating" src="https://imgs.xkcd.com/comics/workflow.png"/>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Build Dependencies
|
|
||||||
|
|
||||||
- Go 1.10.3+
|
|
||||||
- On macOS, you need Xcode or Command Line Tools for Xcode (`xcode-select --install`) for required headers and libraries.
|
|
||||||
- On Ubuntu/Debian-like Linux distributions, you need `libgl1-mesa-dev xorg-dev`.
|
|
||||||
- On CentOS/Fedora-like Linux distributions, you need `libX11-devel libXcursor-devel libXrandr-devel libXinerama-devel mesa-libGL-devel libXi-devel`.
|
|
||||||
|
|
||||||
## Platform Support
|
## Platform Support
|
||||||
|
|
||||||
| Platform | Supported |
|
| Platform | Supported |
|
||||||
|
@ -47,25 +46,12 @@ Ensure you have your latest graphics card drivers installed before use.
|
||||||
| MacOSX | ⏳ |
|
| MacOSX | ⏳ |
|
||||||
| Windows | ⏳ |
|
| Windows | ⏳ |
|
||||||
|
|
||||||
## Planned Features
|
## Build Dependencies
|
||||||
|
|
||||||
| Feature | Done | Notes |
|
- Go 1.10.3+
|
||||||
|-----------------------------|------|-------|
|
- On macOS, you need Xcode or Command Line Tools for Xcode (`xcode-select --install`) for required headers and libraries.
|
||||||
| Pty allocation | ✔ |
|
- On Ubuntu/Debian-like Linux distributions, you need `libgl1-mesa-dev xorg-dev`.
|
||||||
| OpenGL rendering | ✔ |
|
- On CentOS/Fedora-like Linux distributions, you need `libX11-devel libXcursor-devel libXrandr-devel libXinerama-devel mesa-libGL-devel libXi-devel`.
|
||||||
| 8-bit (256) colour | ✔ |
|
|
||||||
| 24-bit (true) colour | ✔ |
|
|
||||||
| Resizing/content reordering | ✔ |
|
|
||||||
| ANSI escape codes | ✔ |
|
|
||||||
| UTF-8 input | ✔ |
|
|
||||||
| UTF-8 output | ✔ |
|
|
||||||
| Copy/paste | ✔ |
|
|
||||||
| Customisable colour schemes | ✔ |
|
|
||||||
| Config file | ✔ |
|
|
||||||
| Scrolling | ✔ |
|
|
||||||
| Mouse interaction | ✔ |
|
|
||||||
| Clickable URLs | ✔ |
|
|
||||||
| Sweet render effects | |
|
|
||||||
|
|
||||||
## Keyboard Shortcuts
|
## Keyboard Shortcuts
|
||||||
|
|
||||||
|
|
|
@ -40,11 +40,11 @@ func (cell *Cell) DrawImage(x, y float32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var tex uint32
|
var tex uint32
|
||||||
|
gl.Enable(gl.TEXTURE_2D)
|
||||||
gl.GenTextures(1, &tex)
|
gl.GenTextures(1, &tex)
|
||||||
gl.BindTexture(gl.TEXTURE_2D, tex)
|
gl.BindTexture(gl.TEXTURE_2D, tex)
|
||||||
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
|
||||||
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
|
||||||
|
|
||||||
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||||
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||||
|
|
||||||
|
@ -60,6 +60,9 @@ func (cell *Cell) DrawImage(x, y float32) {
|
||||||
gl.Ptr(cell.image.Pix),
|
gl.Ptr(cell.image.Pix),
|
||||||
)
|
)
|
||||||
gl.BindTexture(gl.TEXTURE_2D, 0)
|
gl.BindTexture(gl.TEXTURE_2D, 0)
|
||||||
|
gl.Disable(gl.TEXTURE_2D)
|
||||||
|
|
||||||
|
gl.Disable(gl.BLEND)
|
||||||
|
|
||||||
var w float32 = float32(cell.image.Bounds().Size().X)
|
var w float32 = float32(cell.image.Bounds().Size().X)
|
||||||
var h float32 = float32(cell.image.Bounds().Size().Y)
|
var h float32 = float32(cell.image.Bounds().Size().Y)
|
||||||
|
@ -67,6 +70,7 @@ func (cell *Cell) DrawImage(x, y float32) {
|
||||||
var readFboId uint32
|
var readFboId uint32
|
||||||
gl.GenFramebuffers(1, &readFboId)
|
gl.GenFramebuffers(1, &readFboId)
|
||||||
gl.BindFramebuffer(gl.READ_FRAMEBUFFER, readFboId)
|
gl.BindFramebuffer(gl.READ_FRAMEBUFFER, readFboId)
|
||||||
|
|
||||||
gl.FramebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
|
gl.FramebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
|
||||||
gl.TEXTURE_2D, tex, 0)
|
gl.TEXTURE_2D, tex, 0)
|
||||||
gl.BlitFramebuffer(0, 0, int32(w), int32(h),
|
gl.BlitFramebuffer(0, 0, int32(w), int32(h),
|
||||||
|
@ -74,6 +78,7 @@ func (cell *Cell) DrawImage(x, y float32) {
|
||||||
gl.COLOR_BUFFER_BIT, gl.LINEAR)
|
gl.COLOR_BUFFER_BIT, gl.LINEAR)
|
||||||
gl.BindFramebuffer(gl.READ_FRAMEBUFFER, 0)
|
gl.BindFramebuffer(gl.READ_FRAMEBUFFER, 0)
|
||||||
gl.DeleteFramebuffers(1, &readFboId)
|
gl.DeleteFramebuffers(1, &readFboId)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cell *Cell) Attr() CellAttributes {
|
func (cell *Cell) Attr() CellAttributes {
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,8 +6,6 @@ import (
|
||||||
"image/color"
|
"image/color"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-gl/gl/v2.1/gl"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Sixel struct {
|
type Sixel struct {
|
||||||
|
@ -32,7 +30,7 @@ func decompress(data string) string {
|
||||||
inMarker = true
|
inMarker = true
|
||||||
countStr = ""
|
countStr = ""
|
||||||
} else {
|
} else {
|
||||||
output = fmt.Sprintf("%s%c", output, r)
|
output += string(r)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -41,9 +39,7 @@ func decompress(data string) string {
|
||||||
countStr = fmt.Sprintf("%s%c", countStr, r)
|
countStr = fmt.Sprintf("%s%c", countStr, r)
|
||||||
} else {
|
} else {
|
||||||
count, _ := strconv.Atoi(countStr)
|
count, _ := strconv.Atoi(countStr)
|
||||||
for i := 0; i < count; i++ {
|
output += strings.Repeat(string(r), count)
|
||||||
output = fmt.Sprintf("%s%c", output, r)
|
|
||||||
}
|
|
||||||
inMarker = false
|
inMarker = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,9 +81,9 @@ func ParseString(data string) (*Sixel, error) {
|
||||||
ratio = 5
|
ratio = 5
|
||||||
case "2":
|
case "2":
|
||||||
ratio = 3
|
ratio = 3
|
||||||
case "", "3", "4", "5", "6":
|
case "3", "4", "5", "6":
|
||||||
ratio = 2
|
ratio = 2
|
||||||
case "7", "8", "9":
|
case "7", "8", "9", "":
|
||||||
ratio = 1
|
ratio = 1
|
||||||
}
|
}
|
||||||
if len(headers) > 1 {
|
if len(headers) > 1 {
|
||||||
|
@ -165,37 +161,6 @@ func ParseString(data string) (*Sixel, error) {
|
||||||
return &six, nil
|
return &six, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (six *Sixel) Draw() error {
|
|
||||||
rgba := six.RGBA()
|
|
||||||
|
|
||||||
var handle uint32
|
|
||||||
gl.GenTextures(1, &handle)
|
|
||||||
|
|
||||||
target := uint32(gl.TEXTURE_2D)
|
|
||||||
internalFmt := int32(gl.SRGB_ALPHA)
|
|
||||||
format := uint32(gl.RGBA)
|
|
||||||
width := int32(rgba.Rect.Size().X)
|
|
||||||
height := int32(rgba.Rect.Size().Y)
|
|
||||||
pixType := uint32(gl.UNSIGNED_BYTE)
|
|
||||||
dataPtr := gl.Ptr(rgba.Pix)
|
|
||||||
|
|
||||||
gl.ActiveTexture(gl.TEXTURE0)
|
|
||||||
gl.BindTexture(target, handle)
|
|
||||||
|
|
||||||
// set the texture wrapping/filtering options (applies to current bound texture obj)
|
|
||||||
// TODO-cs
|
|
||||||
//gl.TexParameteri(texture.target, gl.TEXTURE_WRAP_R, wrapR)
|
|
||||||
//gl.TexParameteri(texture.target, gl.TEXTURE_WRAP_S, wrapS)
|
|
||||||
gl.TexParameteri(target, gl.TEXTURE_MIN_FILTER, gl.LINEAR) // minification filter
|
|
||||||
gl.TexParameteri(target, gl.TEXTURE_MAG_FILTER, gl.LINEAR) // magnification filter
|
|
||||||
|
|
||||||
gl.TexImage2D(target, 0, internalFmt, width, height, 0, format, pixType, dataPtr)
|
|
||||||
|
|
||||||
// unbind
|
|
||||||
gl.BindTexture(target, 0)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (six *Sixel) setPixel(x, y uint, c colour, vhRatio uint) {
|
func (six *Sixel) setPixel(x, y uint, c colour, vhRatio uint) {
|
||||||
|
|
||||||
if six.px == nil {
|
if six.px == nil {
|
||||||
|
@ -227,11 +192,11 @@ func (six *Sixel) RGBA() *image.RGBA {
|
||||||
|
|
||||||
for x, r := range six.px {
|
for x, r := range six.px {
|
||||||
for y, colour := range r {
|
for y, colour := range r {
|
||||||
rgba.SetRGBA(int(x), int(six.height)-int(y), color.RGBA{
|
rgba.Set(int(x), int(six.height)-int(y), color.RGBA{
|
||||||
colour[0],
|
R: colour[0],
|
||||||
colour[1],
|
G: colour[1],
|
||||||
colour[2],
|
B: colour[2],
|
||||||
255,
|
A: 255,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,9 +2,11 @@ package terminal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/draw"
|
||||||
"math"
|
"math"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-gl/gl/all-core/gl"
|
|
||||||
"github.com/liamg/aminal/sixel"
|
"github.com/liamg/aminal/sixel"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -18,29 +20,53 @@ func sixelHandler(pty chan rune, terminal *Terminal) error {
|
||||||
_ = <-pty // swallow \ or bell
|
_ = <-pty // swallow \ or bell
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
if b >= 33 {
|
||||||
data = append(data, b)
|
data = append(data, b)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
six, err := sixel.ParseString(string(data))
|
six, err := sixel.ParseString(string(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to parse sixel data: %s", err)
|
return fmt.Errorf("Failed to parse sixel data: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
originalImage := six.RGBA()
|
||||||
|
|
||||||
|
w := originalImage.Bounds().Size().X
|
||||||
|
h := originalImage.Bounds().Size().Y
|
||||||
|
|
||||||
x, y := terminal.ActiveBuffer().CursorColumn(), terminal.ActiveBuffer().CursorLine()
|
x, y := terminal.ActiveBuffer().CursorColumn(), terminal.ActiveBuffer().CursorLine()
|
||||||
terminal.ActiveBuffer().Write(' ')
|
|
||||||
cell := terminal.ActiveBuffer().GetCell(x, y)
|
fromBottom := int(terminal.ActiveBuffer().ViewHeight() - y)
|
||||||
if cell == nil {
|
lines := int(math.Ceil(float64(h) / float64(terminal.charHeight)))
|
||||||
return fmt.Errorf("Missing cell for sixel")
|
if fromBottom < lines+2 {
|
||||||
|
y -= (uint16(lines+2) - uint16(fromBottom))
|
||||||
}
|
}
|
||||||
|
for l := 0; l <= int(lines); l++ {
|
||||||
gl.UseProgram(terminal.program)
|
terminal.ActiveBuffer().Write([]rune(strings.Repeat(" ", int(terminal.ActiveBuffer().ViewWidth())))...)
|
||||||
cell.SetImage(six.RGBA())
|
|
||||||
|
|
||||||
imageHeight := float64(cell.Image().Bounds().Size().Y)
|
|
||||||
lines := int(math.Ceil(imageHeight / float64(terminal.charHeight)))
|
|
||||||
for l := 0; l <= int(lines+1); l++ {
|
|
||||||
terminal.ActiveBuffer().NewLine()
|
terminal.ActiveBuffer().NewLine()
|
||||||
}
|
}
|
||||||
|
cols := int(math.Ceil(float64(w) / float64(terminal.charWidth)))
|
||||||
|
|
||||||
|
for offsetY := 0; offsetY < lines-1; offsetY++ {
|
||||||
|
for offsetX := 0; offsetX < cols-1; offsetX++ {
|
||||||
|
|
||||||
|
cell := terminal.ActiveBuffer().GetCell(x+uint16(offsetX), y+uint16((lines-2)-offsetY))
|
||||||
|
if cell == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
img := originalImage.SubImage(image.Rect(
|
||||||
|
offsetX*int(terminal.charWidth),
|
||||||
|
offsetY*int(terminal.charHeight),
|
||||||
|
(offsetX*int(terminal.charWidth))+int(terminal.charWidth),
|
||||||
|
(offsetY*int(terminal.charHeight))+int(terminal.charHeight),
|
||||||
|
))
|
||||||
|
|
||||||
|
rgba := image.NewRGBA(image.Rect(0, 0, int(terminal.charWidth), int(terminal.charHeight)))
|
||||||
|
draw.Draw(rgba, rgba.Bounds(), img, img.Bounds().Min, draw.Src)
|
||||||
|
cell.SetImage(rgba)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue