finished sixel support

This commit is contained in:
Liam Galvin 2018-10-28 15:26:12 +00:00
parent 20c3c0cb14
commit 78d67302b4
6 changed files with 67 additions and 89 deletions

View File

@ -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.
Sixels are now supported.
![Example sixel](sixel.png)
## Aims
- Full unicode support
- Unicode support
- OpenGL rendering
- Full customisation options
- 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_
- Bullshit graphical effects
- Multi platform support
- Sixel support
## 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"/>
</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 | Supported |
@ -47,25 +46,12 @@ Ensure you have your latest graphics card drivers installed before use.
| MacOSX | ⏳ |
| Windows | ⏳ |
## Planned Features
## Build Dependencies
| Feature | Done | Notes |
|-----------------------------|------|-------|
| Pty allocation | ✔ |
| OpenGL rendering | ✔ |
| 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 | |
- 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`.
## Keyboard Shortcuts

View File

@ -40,11 +40,11 @@ func (cell *Cell) DrawImage(x, y float32) {
}
var tex uint32
gl.Enable(gl.TEXTURE_2D)
gl.GenTextures(1, &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_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_T, gl.CLAMP_TO_EDGE)
@ -60,6 +60,9 @@ func (cell *Cell) DrawImage(x, y float32) {
gl.Ptr(cell.image.Pix),
)
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 h float32 = float32(cell.image.Bounds().Size().Y)
@ -67,6 +70,7 @@ func (cell *Cell) DrawImage(x, y float32) {
var readFboId uint32
gl.GenFramebuffers(1, &readFboId)
gl.BindFramebuffer(gl.READ_FRAMEBUFFER, readFboId)
gl.FramebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D, tex, 0)
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.BindFramebuffer(gl.READ_FRAMEBUFFER, 0)
gl.DeleteFramebuffers(1, &readFboId)
}
func (cell *Cell) Attr() CellAttributes {

File diff suppressed because one or more lines are too long

BIN
sixel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

View File

@ -6,8 +6,6 @@ import (
"image/color"
"strconv"
"strings"
"github.com/go-gl/gl/v2.1/gl"
)
type Sixel struct {
@ -32,7 +30,7 @@ func decompress(data string) string {
inMarker = true
countStr = ""
} else {
output = fmt.Sprintf("%s%c", output, r)
output += string(r)
}
continue
}
@ -41,9 +39,7 @@ func decompress(data string) string {
countStr = fmt.Sprintf("%s%c", countStr, r)
} else {
count, _ := strconv.Atoi(countStr)
for i := 0; i < count; i++ {
output = fmt.Sprintf("%s%c", output, r)
}
output += strings.Repeat(string(r), count)
inMarker = false
}
}
@ -85,9 +81,9 @@ func ParseString(data string) (*Sixel, error) {
ratio = 5
case "2":
ratio = 3
case "", "3", "4", "5", "6":
case "3", "4", "5", "6":
ratio = 2
case "7", "8", "9":
case "7", "8", "9", "":
ratio = 1
}
if len(headers) > 1 {
@ -165,37 +161,6 @@ func ParseString(data string) (*Sixel, error) {
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) {
if six.px == nil {
@ -227,11 +192,11 @@ func (six *Sixel) RGBA() *image.RGBA {
for x, r := range six.px {
for y, colour := range r {
rgba.SetRGBA(int(x), int(six.height)-int(y), color.RGBA{
colour[0],
colour[1],
colour[2],
255,
rgba.Set(int(x), int(six.height)-int(y), color.RGBA{
R: colour[0],
G: colour[1],
B: colour[2],
A: 255,
})
}
}

View File

@ -2,9 +2,11 @@ package terminal
import (
"fmt"
"image"
"image/draw"
"math"
"strings"
"github.com/go-gl/gl/all-core/gl"
"github.com/liamg/aminal/sixel"
)
@ -18,7 +20,9 @@ func sixelHandler(pty chan rune, terminal *Terminal) error {
_ = <-pty // swallow \ or bell
break
}
data = append(data, b)
if b >= 33 {
data = append(data, b)
}
}
six, err := sixel.ParseString(string(data))
@ -26,21 +30,43 @@ func sixelHandler(pty chan rune, terminal *Terminal) error {
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()
terminal.ActiveBuffer().Write(' ')
cell := terminal.ActiveBuffer().GetCell(x, y)
if cell == nil {
return fmt.Errorf("Missing cell for sixel")
fromBottom := int(terminal.ActiveBuffer().ViewHeight() - y)
lines := int(math.Ceil(float64(h) / float64(terminal.charHeight)))
if fromBottom < lines+2 {
y -= (uint16(lines+2) - uint16(fromBottom))
}
gl.UseProgram(terminal.program)
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++ {
for l := 0; l <= int(lines); l++ {
terminal.ActiveBuffer().Write([]rune(strings.Repeat(" ", int(terminal.ActiveBuffer().ViewWidth())))...)
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
}