Initial commit
This commit is contained in:
commit
c240d1ed40
7
go.mod
Normal file
7
go.mod
Normal file
@ -0,0 +1,7 @@
|
||||
module git.redxen.eu/caskd/v6canvas
|
||||
|
||||
go 1.20
|
||||
|
||||
require golang.org/x/net v0.8.0
|
||||
|
||||
require golang.org/x/sys v0.6.0 // indirect
|
4
go.sum
Normal file
4
go.sum
Normal file
@ -0,0 +1,4 @@
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
154
main.go
Normal file
154
main.go
Normal file
@ -0,0 +1,154 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
_ "image/png"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/icmp"
|
||||
"golang.org/x/net/ipv6"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var (
|
||||
dt uint
|
||||
err error
|
||||
)
|
||||
flag.UintVar(&dt, "timeout", 5000, "Frame display time (ms)")
|
||||
flag.Parse()
|
||||
|
||||
var (
|
||||
up = make(chan image.Image)
|
||||
lo = make(chan image.Image)
|
||||
dx = make(chan pixdelta)
|
||||
)
|
||||
|
||||
c, err := icmp.ListenPacket("udp6", "::")
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to listen for ICMP packets:", err)
|
||||
}
|
||||
go sendDelta(dx, c)
|
||||
go syncColors(up, lo, dx)
|
||||
|
||||
var imgs [2]image.Image
|
||||
for i := range imgs {
|
||||
imgs[i] = image.NewRGBA(image.Rect(0, 0, 511, 511))
|
||||
}
|
||||
for _, v := range flag.Args() {
|
||||
f, err := os.Open(v)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to open image:", err)
|
||||
}
|
||||
imgs[0] = imgs[1]
|
||||
imgs[1], _, err = image.Decode(f)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to decode image:", err)
|
||||
}
|
||||
up <- imgs[0]
|
||||
lo <- imgs[1]
|
||||
time.Sleep(time.Duration(dt) * time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
func sendDelta(d chan pixdelta, c *icmp.PacketConn) {
|
||||
pm := icmp.Message{
|
||||
Type: ipv6.ICMPTypeEchoRequest, Code: 0,
|
||||
Body: &icmp.Echo{Seq: 1},
|
||||
}
|
||||
|
||||
bb, err := pm.Marshal(nil)
|
||||
if err != nil {
|
||||
log.Fatalln("Failed to encode ICMP packet")
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case delta := <-d:
|
||||
dest := &net.UDPAddr{
|
||||
IP: convV6(delta.p, delta.c),
|
||||
}
|
||||
|
||||
if _, err := c.WriteTo(bb, dest); err != nil {
|
||||
log.Println("Failed to send packet to:", dest)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
func syncColors(upstream, local chan image.Image, dx chan pixdelta) {
|
||||
var (
|
||||
oimg, nimg image.Image
|
||||
)
|
||||
|
||||
oimg = nil
|
||||
nimg = nil
|
||||
for {
|
||||
select {
|
||||
case nimg = <-local:
|
||||
break
|
||||
case oimg = <-upstream:
|
||||
break
|
||||
}
|
||||
if oimg == nil || nimg == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
jobs := uint64(0)
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
b := nimg.Bounds()
|
||||
for x := 0; x < b.Dx(); x++ {
|
||||
for y := 0; y < b.Dy(); y++ {
|
||||
wg.Add(1)
|
||||
go comparePixel(oimg, nimg, image.Point{X: x, Y: y}, dx, wg)
|
||||
jobs++
|
||||
}
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
}
|
||||
|
||||
// Framebuffer
|
||||
|
||||
type pixdelta struct {
|
||||
p image.Point
|
||||
c color.Color
|
||||
}
|
||||
|
||||
func comparePixel(a, b image.Image, loc image.Point, r chan pixdelta, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
car, cab, cag, _ := a.At(loc.X, loc.Y).RGBA()
|
||||
cbr, cbb, cbg, cba := b.At(loc.X, loc.Y).RGBA()
|
||||
if (cba == 0xFFFF) && !(car == cbr && cag == cbg && cab == cbb) {
|
||||
r <- pixdelta{c: b.At(loc.X, loc.Y), p: loc}
|
||||
}
|
||||
}
|
||||
|
||||
// Network
|
||||
|
||||
// fdcf:8538:9ad5:3333:XXXX:YYYY:11RR:GGBB
|
||||
func convV6(p image.Point, c color.Color) (addr net.IP) {
|
||||
addr = net.IP{
|
||||
0xfd, 0xcf, 0x85, 0x38, 0x9a, 0xd5, 0x33, 0x33,
|
||||
}
|
||||
addr = append(addr, split2Bytes(uint16(p.X))...)
|
||||
addr = append(addr, split2Bytes(uint16(p.Y))...)
|
||||
r, g, b, _ := c.RGBA()
|
||||
addr = append(addr, 0x11, uint8(r), uint8(g), uint8(b))
|
||||
return
|
||||
}
|
||||
|
||||
func split2Bytes(s uint16) []uint8 {
|
||||
return []uint8{
|
||||
uint8((s & (0xFF << 8)) >> 8),
|
||||
uint8(s & 0xFF),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user